From ec3dc2d4777f6cabaf9ba5573dcb0fc5adf7731e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Tue, 27 Oct 2015 16:25:33 -0700 Subject: [PATCH 01/53] 1.4 release notes --- RELEASES.md | 169 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 169 insertions(+) diff --git a/RELEASES.md b/RELEASES.md index 9b61ce0e05414..2f1dac4a18781 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,3 +1,172 @@ +Version 1.4.0 (October 2015) +============================ + +* ~1200 changes, numerous bugfixes + +Highlights +---------- + +* Windows builds targeting the 64-bit MSVC ABI and linker (instead of + GNU) are now supported and recommended for use. + +Breaking Changes +---------------- + +* [Several changes have been made to fix type soundness and improve + the behavior of associated types][sound]. See [RFC 1214]. Although + we have mostly introduced these changes as warnings this release, to + become errors next release, there are still some scenarios that will + see immediate breakage. +* [The `str::lines` and `BufRead::lines` iterators treat `\r\n` as + line breaks in addition to `\n`][crlf]. +* [Loans of `'static` lifetime extend to the end of a function][stat]. + +Language +-------- + +* `use` statements that import multiple items [can now rename + them][i], as in `use foo::{bar as kitten, baz as puppy}`. +* [Binops work correctly on fat pointers][binfat]. +* `pub extern crate`, which does not behave as expected, [issues a + warning][pec] until a better solution is found. + +Libraries +--------- + +* [Many APIs were stabilized][stab]: `>::into_string`, + [`Arc::downgrade`], [`Arc::get_mut`], [`Arc::make_mut`], + [`Arc::try_unwrap`], [`Box::from_raw`], [`Box::into_raw`], [`CStr::to_str`], + [`CStr::to_string_lossy`], [`CString::from_raw`], [`CString::into_raw`], + [`IntoRawFd::into_raw_fd`], [`IntoRawFd`], + `IntoRawHandle::into_raw_handle`, `IntoRawHandle`, + `IntoRawSocket::into_raw_socket`, `IntoRawSocket`, [`Rc::downgrade`], + [`Rc::get_mut`], [`Rc::make_mut`], [`Rc::try_unwrap`], [`Result::expect`], + [`String::into_boxed_str`], [`TcpStream::read_timeout`], + [`TcpStream::set_read_timeout`], [`TcpStream::set_write_timeout`], + [`TcpStream::write_timeout`], [`UdpSocket::read_timeout`], + [`UdpSocket::set_read_timeout`], [`UdpSocket::set_write_timeout`], + [`UdpSocket::write_timeout`], `Vec::append`, `Vec::split_off`, + [`VecDeque::append`], [`VecDeque::retain`], [`VecDeque::split_off`], + [`rc::Weak::upgrade`], [`rc::Weak`], [`slice::Iter::as_slice`], + [`slice::IterMut::into_slice`], [`str::CharIndices::as_str`], + [`str::Chars::as_str`], [`str::split_at_mut`], [`str::split_at`], + [`sync::Weak::upgrade`], [`sync::Weak`], [`thread::park_timeout`], + [`thread::sleep`]. +* [Some APIs were deprecated][dep]: `BTreeMap::with_b`, + `BTreeSet::with_b`, `Option::as_mut_slice`, `Option::as_slice`, + `Result::as_mut_slice`, `Result::as_slice`, `f32::from_str_radix`, + `f64::from_str_radix`. +* [Reverse-searching strings is faster with the 'two-way' + algorithm][s]. +* [`std::io::copy` allows `?Sized` arguments][cc]. +* The `Windows`, `Chunks`, and `ChunksMut` iterators over slices all + [override `count`, `nth` and `last` with an O(1) + implementation][it]. +* [`Default` is implemented for arrays up to `[T; 32]`][d]. +* [`IntoRawFd` has been added to the Unix-specific prelude, + `IntoRawSocket` and `IntoRawHandle` to the Windows-specific + prelude][pr]. +* [`Extend` and `FromIterator` and + `Result<&T>`][into]. +* [`HashMap` and `HashSet` implement `Extend<&T>` where `T: + Copy`][ext] as part of [RFC 839]. +* [`BinaryHeap` implements `Debug`][bh2]. +* [`Borrow` and `BorrowMut` are implemented for fixed-size + arrays][bm]. +* [`extern fn`s of with the "Rust" and "C" ABIs implement common + traits including `Eq`, `Ord`, `Debug`, `Hash`][fp]. +* [String comparison is faster][faststr]. +* `&mut T` where `T: Write` [also implements `Write`][mutw]. +* [A stable regression in `VecDec::push_back` that caused panics for + zero-sized types was fixed][vd]. +* [Function pointers implement traits for up to 12 parameters][fp2]. + +Miscellaneous +------------- + +* The compiler [no longer uses the 'morestack' feature to prevent + stack overflow][mm]. Instead it uses guard pages and stack + probes (though stack probes are not yet implemented on any platform + but Windows). +* [The compiler matches traits faster when projections are involved][p]. +* The 'improper_ctypes' lint [no longer warns about use of `isize` and + `usize`][ffi]. +* [Cargo now displays useful information about what its doing during + `cargo update`][cu]. + +[`Arc::downgrade`]: http://doc.rust-lang.org/nightly/alloc/arc/struct.Arc.html#method.downgrade +[`Arc::make_mut`]: http://doc.rust-lang.org/nightly/alloc/arc/struct.Arc.html#method.make_mut +[`Arc::get_mut`]: http://doc.rust-lang.org/nightly/alloc/arc/struct.Arc.html#method.get_mut +[`Arc::try_unwrap`]: http://doc.rust-lang.org/nightly/alloc/arc/struct.Arc.html#method.try_unwrap +[`Box::from_raw`]: http://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.from_raw +[`Box::into_raw`]: http://doc.rust-lang.org/nightly/alloc/boxed/struct.Box.html#method.into_raw +[`CStr::to_str`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.to_str +[`CStr::to_string_lossy`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CStr.html#method.to_string_lossy +[`CString::from_raw`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.from_raw +[`CString::into_raw`]: http://doc.rust-lang.org/nightly/std/ffi/struct.CString.html#method.into_raw +[`IntoRawFd::into_raw_fd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.IntoRawFd.html#tymethod.into_raw_fd +[`IntoRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.IntoRawFd.html +[`Rc::downgrade`]: http://doc.rust-lang.org/nightly/alloc/rc/struct.Rc.html#method.downgrade +[`Rc::get_mut`]: http://doc.rust-lang.org/nightly/alloc/rc/struct.Rc.html#method.get_mut +[`Rc::make_mut`]: http://doc.rust-lang.org/nightly/alloc/rc/struct.Rc.html#method.make_mut +[`Rc::try_unwrap`]: http://doc.rust-lang.org/nightly/alloc/rc/struct.Rc.html#method.try_unwrap +[`Result::expect`]: http://doc.rust-lang.org/nightly/core/result/enum.Result.html#method.expect +[`String::into_boxed_str`]: http://doc.rust-lang.org/nightly/collections/string/struct.String.html#method.into_boxed_str +[`TcpStream::read_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.read_timeout +[`TcpStream::set_read_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_read_timeout +[`TcpStream::write_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.write_timeout +[`TcpStream::set_write_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_write_timeout +[`UdpSocket::read_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.read_timeout +[`UdpSocket::set_read_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_read_timeout +[`UdpSocket::write_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.write_timeout +[`UdpSocket::set_write_timeout`]: http://doc.rust-lang.org/nightly/std/net/struct.TcpStream.html#method.set_write_timeout +[`VecDeque::append`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.append +[`VecDeque::retain`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.retain +[`VecDeque::split_off`]: http://doc.rust-lang.org/nightly/std/collections/struct.VecDeque.html#method.split_off +[`rc::Weak::upgrade`]: http://doc.rust-lang.org/nightly/std/rc/struct.Weak.html#method.upgrade +[`rc::Weak`]: http://doc.rust-lang.org/nightly/std/rc/struct.Weak.html +[`slice::Iter::as_slice`]: http://doc.rust-lang.org/nightly/std/slice/struct.Iter.html#method.as_slice +[`slice::IterMut::into_slice`]: http://doc.rust-lang.org/nightly/std/slice/struct.IterMut.html#method.into_slice +[`str::CharIndices::as_str`]: http://doc.rust-lang.org/nightly/std/str/struct.CharIndices.html#method.as_str +[`str::Chars::as_str`]: http://doc.rust-lang.org/nightly/std/str/struct.Chars.html#method.as_str +[`str::split_at_mut`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_at_mut +[`str::split_at`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_at +[`sync::Weak::upgrade`]: http://doc.rust-lang.org/nightly/std/sync/struct.Weak.html#method.upgrade +[`sync::Weak`]: http://doc.rust-lang.org/nightly/std/sync/struct.Weak.html +[`thread::park_timeout`]: http://doc.rust-lang.org/nightly/std/thread/fn.park_timeout.html +[`thread::sleep`]: http://doc.rust-lang.org/nightly/std/thread/fn.sleep.html +[bh2]: https://github.com/rust-lang/rust/pull/28156 +[binfat]: https://github.com/rust-lang/rust/pull/28270 +[bm]: https://github.com/rust-lang/rust/pull/28197 +[cc]: https://github.com/rust-lang/rust/pull/27531 +[crlf]: https://github.com/rust-lang/rust/pull/28034 +[cu]: https://github.com/rust-lang/cargo/pull/1931 +[d]: https://github.com/rust-lang/rust/pull/27825 +[dep]: https://github.com/rust-lang/rust/pull/28339 +[es]: https://github.com/rust-lang/rust/pull/27956 +[ext]: https://github.com/rust-lang/rust/pull/28094 +[faststr]: https://github.com/rust-lang/rust/pull/28338 +[ffi]: https://github.com/rust-lang/rust/pull/28779 +[fp]: https://github.com/rust-lang/rust/pull/28268 +[fp2]: https://github.com/rust-lang/rust/pull/28560 +[i]: https://github.com/rust-lang/rust/pull/27451 +[into]: https://github.com/rust-lang/rust/pull/28039 +[it]: https://github.com/rust-lang/rust/pull/27652 +[mm]: https://github.com/rust-lang/rust/pull/27338 +[mutw]: https://github.com/rust-lang/rust/pull/28368 +[sound]: https://github.com/rust-lang/rust/pull/27641 +[p]: https://github.com/rust-lang/rust/pull/27866 +[pec]: https://github.com/rust-lang/rust/pull/28486 +[pr]: https://github.com/rust-lang/rust/pull/27896 +[RFC 839]: https://github.com/rust-lang/rfcs/blob/master/text/0839-embrace-extend-extinguish.md +[RFC 1214]: https://github.com/rust-lang/rfcs/blob/master/text/1214-projections-lifetimes-and-wf.md +[s]: https://github.com/rust-lang/rust/pull/27474 +[stab]: https://github.com/rust-lang/rust/pull/28339 +[stat]: https://github.com/rust-lang/rust/pull/28321 +[vd]: https://github.com/rust-lang/rust/pull/28494 + Version 1.3.0 (2015-09-17) ============================== From 018c468e1807e01d0a1c9092b93e496d9ae7606a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 29 Oct 2015 11:36:56 -0700 Subject: [PATCH 02/53] Address release notes feedback --- RELEASES.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 2f1dac4a18781..ada5649ec6e17 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -20,6 +20,12 @@ Breaking Changes * [The `str::lines` and `BufRead::lines` iterators treat `\r\n` as line breaks in addition to `\n`][crlf]. * [Loans of `'static` lifetime extend to the end of a function][stat]. +* [`str::parse` no longer introduces avoidable rounding error when + parsing floating point numbers. Together with earlier changes to + float formatting/output, "round trips" like f.to_string().parse() + now preserve the value of f exactly. Additionally, leading plus + signs are now accepted][fp3]. + Language -------- @@ -68,19 +74,22 @@ Libraries prelude][pr]. * [`Extend` and `FromIterator` and - `Result<&T>`][into]. +* [`IntoIterator` is implemented for references into `Option` and + `Result`][into2]. * [`HashMap` and `HashSet` implement `Extend<&T>` where `T: - Copy`][ext] as part of [RFC 839]. + Copy`][ext] as part of [RFC 839]. This will cause type inferance + breakage in rare situations. * [`BinaryHeap` implements `Debug`][bh2]. * [`Borrow` and `BorrowMut` are implemented for fixed-size arrays][bm]. -* [`extern fn`s of with the "Rust" and "C" ABIs implement common +* [`extern fn`s with the "Rust" and "C" ABIs implement common traits including `Eq`, `Ord`, `Debug`, `Hash`][fp]. * [String comparison is faster][faststr]. -* `&mut T` where `T: Write` [also implements `Write`][mutw]. -* [A stable regression in `VecDec::push_back` that caused panics for - zero-sized types was fixed][vd]. +* `&mut T` where `T: std::fmt::Write` [also implements + `std::fmt::Write`][mutw]. +* [A stable regression in `VecDeque::push_back` and other + capicity-altering methods that caused panics for zero-sized types + was fixed][vd]. * [Function pointers implement traits for up to 12 parameters][fp2]. Miscellaneous @@ -151,8 +160,9 @@ Miscellaneous [ffi]: https://github.com/rust-lang/rust/pull/28779 [fp]: https://github.com/rust-lang/rust/pull/28268 [fp2]: https://github.com/rust-lang/rust/pull/28560 +[fp3]: https://github.com/rust-lang/rust/pull/27307 [i]: https://github.com/rust-lang/rust/pull/27451 -[into]: https://github.com/rust-lang/rust/pull/28039 +[into2]: https://github.com/rust-lang/rust/pull/28039 [it]: https://github.com/rust-lang/rust/pull/27652 [mm]: https://github.com/rust-lang/rust/pull/27338 [mutw]: https://github.com/rust-lang/rust/pull/28368 From 615275b7b839541f2b25bc5d6a5d443ef701127c Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Thu, 29 Oct 2015 21:11:24 +0200 Subject: [PATCH 03/53] doc: make example more simple --- src/libcore/iter.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 262bfd5de992a..f1199919fcb0e 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -2557,11 +2557,11 @@ pub trait Extend { /// /// ``` /// // You can extend a String with some chars: - /// let mut message = String::from("The first three letters are: "); + /// let mut message = String::from("abc"); /// - /// message.extend(['a', 'b', 'c'].iter()); + /// message.extend(['d', 'e', 'f'].iter()); /// - /// assert_eq!("abc", &message[29..32]); + /// assert_eq!("abcdef", &message); /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn extend>(&mut self, iterable: T); From 37735b4d6d6e0c4acbea2351794abdcd78ff9363 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Wed, 21 Oct 2015 07:06:00 +0200 Subject: [PATCH 04/53] run rustfmt on std::path There was a bunch of manual fixes too... rustfmt isn't quite there yet --- src/libstd/path.rs | 261 ++++++++++++++++++++++++++++----------------- 1 file changed, 165 insertions(+), 96 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index fe12b671235a2..7a4b8e9992c4e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -48,7 +48,8 @@ //! The path APIs are built around the notion of "components", which roughly //! correspond to the substrings between path separators (`/` and, on Windows, //! `\`). The APIs for path parsing are largely specified in terms of the path's -//! components, so it's important to clearly understand how those are determined. +//! components, so it's important to clearly understand how those are +//! determined. //! //! A path can always be reconstructed into an *equivalent* path by //! putting together its components via `push`. Syntactically, the @@ -190,10 +191,9 @@ mod platform { // \\?\UNC\server\share path = &path[4..]; let (server, share) = match parse_two_comps(path, is_verbatim_sep) { - Some((server, share)) => (u8_slice_as_os_str(server), - u8_slice_as_os_str(share)), - None => (u8_slice_as_os_str(path), - u8_slice_as_os_str(&[])), + Some((server, share)) => + (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), + None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), }; return Some(VerbatimUNC(server, share)); } else { @@ -206,7 +206,7 @@ mod platform { return Some(VerbatimDisk(c.to_ascii_uppercase())); } } - let slice = &path[.. idx.unwrap_or(path.len())]; + let slice = &path[..idx.unwrap_or(path.len())]; return Some(Verbatim(u8_slice_as_os_str(slice))); } } else if path.starts_with(b".\\") { @@ -219,10 +219,9 @@ mod platform { match parse_two_comps(path, is_sep_byte) { Some((server, share)) if !server.is_empty() && !share.is_empty() => { // \\server\share - return Some(UNC(u8_slice_as_os_str(server), - u8_slice_as_os_str(share))); + return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); } - _ => () + _ => (), } } else if path.len() > 1 && path[1] == b':' { // C: @@ -237,11 +236,11 @@ mod platform { fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { let first = match path.iter().position(|x| f(*x)) { None => return None, - Some(x) => &path[.. x] + Some(x) => &path[..x], }; - path = &path[(first.len()+1)..]; + path = &path[(first.len() + 1)..]; let idx = path.iter().position(|x| f(*x)); - let second = &path[.. idx.unwrap_or(path.len())]; + let second = &path[..idx.unwrap_or(path.len())]; Some((first, second)) } } @@ -298,15 +297,25 @@ impl<'a> Prefix<'a> { } match *self { Verbatim(x) => 4 + os_str_len(x), - VerbatimUNC(x,y) => 8 + os_str_len(x) + - if os_str_len(y) > 0 { 1 + os_str_len(y) } - else { 0 }, + VerbatimUNC(x, y) => { + 8 + os_str_len(x) + + if os_str_len(y) > 0 { + 1 + os_str_len(y) + } else { + 0 + } + }, VerbatimDisk(_) => 6, - UNC(x,y) => 2 + os_str_len(x) + - if os_str_len(y) > 0 { 1 + os_str_len(y) } - else { 0 }, + UNC(x, y) => { + 2 + os_str_len(x) + + if os_str_len(y) > 0 { + 1 + os_str_len(y) + } else { + 0 + } + }, DeviceNS(x) => 4 + os_str_len(x), - Disk(_) => 2 + Disk(_) => 2, } } @@ -367,14 +376,18 @@ pub const MAIN_SEPARATOR: char = platform::MAIN_SEP; // Iterate through `iter` while it matches `prefix`; return `None` if `prefix` // is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving // `iter` after having exhausted `prefix`. -fn iter_after(mut iter: I, mut prefix: J) -> Option where - I: Iterator + Clone, J: Iterator, A: PartialEq +fn iter_after(mut iter: I, mut prefix: J) -> Option + where I: Iterator + Clone, + J: Iterator, + A: PartialEq { loop { let mut iter_next = iter.clone(); match (iter_next.next(), prefix.next()) { (Some(x), Some(y)) => { - if x != y { return None } + if x != y { + return None; + } } (Some(_), None) => return Some(iter), (None, None) => return Some(iter), @@ -398,14 +411,20 @@ unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { /// Says whether the first byte after the prefix is a separator. fn has_physical_root(s: &[u8], prefix: Option) -> bool { - let path = if let Some(p) = prefix { &s[p.len()..] } else { s }; + let path = if let Some(p) = prefix { + &s[p.len()..] + } else { + s + }; !path.is_empty() && is_sep_byte(path[0]) } // basic workhorse for splitting stem and extension fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { unsafe { - if os_str_as_u8_slice(file) == b".." { return (Some(file), None) } + if os_str_as_u8_slice(file) == b".." { + return (Some(file), None); + } // The unsafety here stems from converting between &OsStr and &[u8] // and back. This is safe to do because (1) we only look at ASCII @@ -581,7 +600,7 @@ pub struct Components<'a> { #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { - inner: Components<'a> + inner: Components<'a>, } impl<'a> Components<'a> { @@ -609,8 +628,16 @@ impl<'a> Components<'a> { // Given the iteration so far, how much of the pre-State::Body path is left? #[inline] fn len_before_body(&self) -> usize { - let root = if self.front <= State::StartDir && self.has_physical_root { 1 } else { 0 }; - let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { 1 } else { 0 }; + let root = if self.front <= State::StartDir && self.has_physical_root { + 1 + } else { + 0 + }; + let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { + 1 + } else { + 0 + }; self.prefix_remaining() + root + cur_dir } @@ -645,28 +672,38 @@ impl<'a> Components<'a> { #[stable(feature = "rust1", since = "1.0.0")] pub fn as_path(&self) -> &'a Path { let mut comps = self.clone(); - if comps.front == State::Body { comps.trim_left(); } - if comps.back == State::Body { comps.trim_right(); } + if comps.front == State::Body { + comps.trim_left(); + } + if comps.back == State::Body { + comps.trim_right(); + } unsafe { Path::from_u8_slice(comps.path) } } /// Is the *original* path rooted? fn has_root(&self) -> bool { - if self.has_physical_root { return true } + if self.has_physical_root { + return true; + } if let Some(p) = self.prefix { - if p.has_implicit_root() { return true } + if p.has_implicit_root() { + return true; + } } false } /// Should the normalized path include a leading . ? fn include_cur_dir(&self) -> bool { - if self.has_root() { return false } + if self.has_root() { + return false; + } let mut iter = self.path[self.prefix_len()..].iter(); match (iter.next(), iter.next()) { (Some(&b'.'), None) => true, (Some(&b'.'), Some(&b)) => self.is_sep_byte(b), - _ => false + _ => false, } } @@ -679,7 +716,7 @@ impl<'a> Components<'a> { // separately via `include_cur_dir` b".." => Some(Component::ParentDir), b"" => None, - _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })) + _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })), } } @@ -689,7 +726,7 @@ impl<'a> Components<'a> { debug_assert!(self.front == State::Body); let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) { None => (0, self.path), - Some(i) => (1, &self.path[.. i]), + Some(i) => (1, &self.path[..i]), }; (comp.len() + extra, self.parse_single_component(comp)) } @@ -700,8 +737,8 @@ impl<'a> Components<'a> { debug_assert!(self.back == State::Body); let start = self.len_before_body(); let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) { - None => (0, &self.path[start ..]), - Some(i) => (1, &self.path[start + i + 1 ..]), + None => (0, &self.path[start..]), + Some(i) => (1, &self.path[start + i + 1..]), }; (comp.len() + extra, self.parse_single_component(comp)) } @@ -713,7 +750,7 @@ impl<'a> Components<'a> { if comp.is_some() { return; } else { - self.path = &self.path[size ..]; + self.path = &self.path[size..]; } } } @@ -725,7 +762,7 @@ impl<'a> Components<'a> { if comp.is_some() { return; } else { - self.path = &self.path[.. self.path.len() - size]; + self.path = &self.path[..self.path.len() - size]; } } } @@ -799,12 +836,12 @@ impl<'a> Iterator for Components<'a> { State::Prefix if self.prefix_len() > 0 => { self.front = State::StartDir; debug_assert!(self.prefix_len() <= self.path.len()); - let raw = &self.path[.. self.prefix_len()]; - self.path = &self.path[self.prefix_len() .. ]; + let raw = &self.path[..self.prefix_len()]; + self.path = &self.path[self.prefix_len()..]; return Some(Component::Prefix(PrefixComponent { raw: unsafe { u8_slice_as_os_str(raw) }, - parsed: self.prefix.unwrap() - })) + parsed: self.prefix.unwrap(), + })); } State::Prefix => { self.front = State::StartDir; @@ -814,26 +851,28 @@ impl<'a> Iterator for Components<'a> { if self.has_physical_root { debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; - return Some(Component::RootDir) + return Some(Component::RootDir); } else if let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir) + return Some(Component::RootDir); } } else if self.include_cur_dir() { debug_assert!(!self.path.is_empty()); self.path = &self.path[1..]; - return Some(Component::CurDir) + return Some(Component::CurDir); } } State::Body if !self.path.is_empty() => { let (size, comp) = self.parse_next_component(); - self.path = &self.path[size ..]; - if comp.is_some() { return comp } + self.path = &self.path[size..]; + if comp.is_some() { + return comp; + } } State::Body => { self.front = State::Done; } - State::Done => unreachable!() + State::Done => unreachable!(), } } None @@ -847,8 +886,10 @@ impl<'a> DoubleEndedIterator for Components<'a> { match self.back { State::Body if self.path.len() > self.len_before_body() => { let (size, comp) = self.parse_next_component_back(); - self.path = &self.path[.. self.path.len() - size]; - if comp.is_some() { return comp } + self.path = &self.path[..self.path.len() - size]; + if comp.is_some() { + return comp; + } } State::Body => { self.back = State::StartDir; @@ -856,29 +897,29 @@ impl<'a> DoubleEndedIterator for Components<'a> { State::StartDir => { self.back = State::Prefix; if self.has_physical_root { - self.path = &self.path[.. self.path.len() - 1]; - return Some(Component::RootDir) + self.path = &self.path[..self.path.len() - 1]; + return Some(Component::RootDir); } else if let Some(p) = self.prefix { if p.has_implicit_root() && !p.is_verbatim() { - return Some(Component::RootDir) + return Some(Component::RootDir); } } else if self.include_cur_dir() { - self.path = &self.path[.. self.path.len() - 1]; - return Some(Component::CurDir) + self.path = &self.path[..self.path.len() - 1]; + return Some(Component::CurDir); } } State::Prefix if self.prefix_len() > 0 => { self.back = State::Done; return Some(Component::Prefix(PrefixComponent { raw: unsafe { u8_slice_as_os_str(self.path) }, - parsed: self.prefix.unwrap() - })) + parsed: self.prefix.unwrap(), + })); } State::Prefix => { self.back = State::Done; - return None + return None; } - State::Done => unreachable!() + State::Done => unreachable!(), } } None @@ -935,7 +976,7 @@ impl<'a> cmp::Ord for Components<'a> { #[derive(Clone, Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct PathBuf { - inner: OsString + inner: OsString, } impl PathBuf { @@ -976,10 +1017,8 @@ impl PathBuf { // in the special case of `C:` on Windows, do *not* add a separator { let comps = self.components(); - if comps.prefix_len() > 0 && - comps.prefix_len() == comps.path.len() && - comps.prefix.unwrap().is_drive() - { + if comps.prefix_len() > 0 && comps.prefix_len() == comps.path.len() && + comps.prefix.unwrap().is_drive() { need_sep = false } } @@ -1012,7 +1051,7 @@ impl PathBuf { self.as_mut_vec().truncate(len); true } - None => false + None => false, } } @@ -1059,7 +1098,9 @@ impl PathBuf { } fn _set_extension(&mut self, extension: &OsStr) -> bool { - if self.file_name().is_none() { return false; } + if self.file_name().is_none() { + return false; + } let mut stem = match self.file_stem() { Some(stem) => stem.to_os_string(), @@ -1161,7 +1202,9 @@ impl<'a> IntoCow<'a, Path> for &'a Path { #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; - fn to_owned(&self) -> PathBuf { self.to_path_buf() } + fn to_owned(&self) -> PathBuf { + self.to_path_buf() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1227,7 +1270,7 @@ impl Into for PathBuf { #[derive(Hash)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Path { - inner: OsStr + inner: OsStr, } impl Path { @@ -1350,8 +1393,7 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn is_absolute(&self) -> bool { - self.has_root() && - (cfg!(unix) || self.prefix().is_some()) + self.has_root() && (cfg!(unix) || self.prefix().is_some()) } /// A path is *relative* if it is not absolute. @@ -1398,7 +1440,7 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn has_root(&self) -> bool { - self.components().has_root() + self.components().has_root() } /// The path without its final component, if any. @@ -1422,11 +1464,13 @@ impl Path { pub fn parent(&self) -> Option<&Path> { let mut comps = self.components(); let comp = comps.next_back(); - comp.and_then(|p| match p { - Component::Normal(_) | - Component::CurDir | - Component::ParentDir => Some(comps.as_path()), - _ => None + comp.and_then(|p| { + match p { + Component::Normal(_) | + Component::CurDir | + Component::ParentDir => Some(comps.as_path()), + _ => None, + } }) } @@ -1448,9 +1492,11 @@ impl Path { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn file_name(&self) -> Option<&OsStr> { - self.components().next_back().and_then(|p| match p { - Component::Normal(p) => Some(p.as_ref()), - _ => None + self.components().next_back().and_then(|p| { + match p { + Component::Normal(p) => Some(p.as_ref()), + _ => None, + } }) } @@ -1460,8 +1506,7 @@ impl Path { /// returns false), then `relative_from` returns `None`. #[unstable(feature = "path_relative_from", reason = "see #23284", issue = "23284")] - pub fn relative_from<'a, P: ?Sized + AsRef>(&'a self, base: &'a P) -> Option<&Path> - { + pub fn relative_from<'a, P: ?Sized + AsRef>(&'a self, base: &'a P) -> Option<&Path> { self._relative_from(base.as_ref()) } @@ -1785,7 +1830,7 @@ impl fmt::Debug for Path { /// Helper struct for safely printing paths with `format!()` and `{}` #[stable(feature = "rust1", since = "1.0.0")] pub struct Display<'a> { - path: &'a Path + path: &'a Path, } #[stable(feature = "rust1", since = "1.0.0")] @@ -1828,32 +1873,44 @@ impl cmp::Ord for Path { #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for Path { - fn as_ref(&self) -> &Path { self } + fn as_ref(&self) -> &Path { + self + } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for OsStr { - fn as_ref(&self) -> &Path { Path::new(self) } + fn as_ref(&self) -> &Path { + Path::new(self) + } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for OsString { - fn as_ref(&self) -> &Path { Path::new(self) } + fn as_ref(&self) -> &Path { + Path::new(self) + } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for str { - fn as_ref(&self) -> &Path { Path::new(self) } + fn as_ref(&self) -> &Path { + Path::new(self) + } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for String { - fn as_ref(&self) -> &Path { Path::new(self) } + fn as_ref(&self) -> &Path { + Path::new(self) + } } #[stable(feature = "rust1", since = "1.0.0")] impl AsRef for PathBuf { - fn as_ref(&self) -> &Path { self } + fn as_ref(&self) -> &Path { + self + } } #[cfg(test)] @@ -2894,20 +2951,26 @@ mod tests { tp!("C:a\\b\\c", "C:d", "C:d"); tp!("C:", r"a\b\c", r"C:a\b\c"); tp!("C:", r"..\a", r"C:..\a"); - tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); + tp!("\\\\server\\share\\foo", + "bar", + "\\\\server\\share\\foo\\bar"); tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); + tp!("\\\\?\\UNC\\server\\share\\foo", + "bar", + "\\\\?\\UNC\\server\\share\\foo\\bar"); tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); // Note: modified from old path API tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); - tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); + tp!("C:\\a", + "\\\\?\\UNC\\server\\share", + "\\\\?\\UNC\\server\\share"); tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); tp!("\\\\.\\foo\\bar", "C:a", "C:a"); // again, not sure about the following, but I'm assuming \\.\ should be verbatim @@ -2960,9 +3023,15 @@ mod tests { tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); - tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); - tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true); - tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); + tp!("\\\\?\\UNC\\server\\share\\a\\b", + "\\\\?\\UNC\\server\\share\\a", + true); + tp!("\\\\?\\UNC\\server\\share\\a", + "\\\\?\\UNC\\server\\share\\", + true); + tp!("\\\\?\\UNC\\server\\share", + "\\\\?\\UNC\\server\\share", + false); tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); tp!("\\\\.\\a", "\\\\.\\a", false); @@ -3028,7 +3097,7 @@ mod tests { tfe!(".", "foo", ".", false); tfe!("foo/", "bar", "foo.bar", true); tfe!("foo/.", "bar", "foo.bar", true); - tfe!("..", "foo", "..", false); + tfe!("..", "foo", "..", false); tfe!("foo/..", "bar", "foo/..", false); tfe!("/", "foo", "/", false); } From ab10cb7443f6c3fd5faf8dcaaf6483833aedced0 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sun, 1 Nov 2015 12:02:19 -0800 Subject: [PATCH 05/53] Clarify Windows gcc setup instructions. --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index acd9cb6afc8d7..9675bc89bf99b 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,7 @@ Read ["Installing Rust"] from [The Book]. # Update package mirrors (may be needed if you have a fresh install of MSYS2) $ pacman -Sy pacman-mirrors - # Choose one based on platform: + # Choose one based on platform: (+++ see the note below +++) $ pacman -S mingw-w64-i686-toolchain $ pacman -S mingw-w64-x86_64-toolchain @@ -89,9 +89,12 @@ Read ["Installing Rust"] from [The Book]. ``` > ***Note:*** gcc versions >= 5 currently have issues building LLVM on Windows > resulting in a segmentation fault when building Rust. In order to avoid this -> it may be necessary to obtain an earlier version of gcc such as 4.9.x. -> Installers for earlier Windows builds of gcc are available at the -> [Mingw-Builds] project. For more information on this see issue #28260. +> it may be necessary to obtain an earlier version of gcc such as 4.9.x. +> Msys's `pacman` will install the latest version, so for the time being it is +> recommended to skip gcc toolchain installation step above and use [Mingw-Builds] +> project's installer instead. Be sure to add gcc `bin` directory to the path +> before running `configure`. +> For more information on this see issue #28260. [Mingw-Builds]: http://sourceforge.net/projects/mingw-w64/ From 363deb0864a47115f26c5ffab0f51a9f52139617 Mon Sep 17 00:00:00 2001 From: Vadim Chugunov Date: Sun, 1 Nov 2015 16:24:51 -0800 Subject: [PATCH 06/53] Formatting --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9675bc89bf99b..5e208a76e0315 100644 --- a/README.md +++ b/README.md @@ -68,7 +68,8 @@ Read ["Installing Rust"] from [The Book]. # Update package mirrors (may be needed if you have a fresh install of MSYS2) $ pacman -Sy pacman-mirrors - # Choose one based on platform: (+++ see the note below +++) + # Choose one based on platform: + # *** see the note below *** $ pacman -S mingw-w64-i686-toolchain $ pacman -S mingw-w64-x86_64-toolchain From a9cbf6c1c1a93817c0e316a9b17439525f7d6a70 Mon Sep 17 00:00:00 2001 From: Ricardo Martins Date: Sat, 31 Oct 2015 23:07:10 +0000 Subject: [PATCH 07/53] Accept tabs as indentation character A line may be indented with both spaces or tabs. All leading whitespace is trimmed, even if it is mixed. --- src/librustdoc/passes.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/librustdoc/passes.rs b/src/librustdoc/passes.rs index 1957f1efa4774..a09ca95dceaa4 100644 --- a/src/librustdoc/passes.rs +++ b/src/librustdoc/passes.rs @@ -331,18 +331,18 @@ pub fn unindent(s: &str) -> String { min_indent } else { saw_first_line = true; - let mut spaces = 0; + let mut whitespace = 0; line.chars().all(|char| { - // Only comparing against space because I wouldn't - // know what to do with mixed whitespace chars - if char == ' ' { - spaces += 1; + // Compare against either space or tab, ignoring whether they + // are mixed or not + if char == ' ' || char == '\t' { + whitespace += 1; true } else { false } }); - cmp::min(min_indent, spaces) + cmp::min(min_indent, whitespace) } }); @@ -407,4 +407,22 @@ mod unindent_tests { let r = unindent(&s); assert_eq!(r, "line1\n\n line2"); } + + #[test] + fn should_unindent_tabs() { + let s = "\tline1\n\tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } + + #[test] + fn should_trim_mixed_indentation() { + let s = "\t line1\n\t line2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + + let s = " \tline1\n \tline2".to_string(); + let r = unindent(&s); + assert_eq!(r, "line1\nline2"); + } } From 6e27448973fcfd553d064cc6534aabb76e5b87a7 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 2 Nov 2015 08:45:38 -0800 Subject: [PATCH 08/53] mk: Add rtstartup to dist Needed for distcheck to pass and to have a working tarball. --- mk/dist.mk | 1 + 1 file changed, 1 insertion(+) diff --git a/mk/dist.mk b/mk/dist.mk index 4cdee8bda9d4c..7ef95d1e78f80 100644 --- a/mk/dist.mk +++ b/mk/dist.mk @@ -59,6 +59,7 @@ PKG_FILES := \ libcoretest \ libbacktrace \ rt \ + rtstartup \ rustllvm \ snapshots.txt \ rust-installer \ From b1ef5302d5456add7b3314cd871d23a2dc45afb5 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Mon, 2 Nov 2015 23:44:53 +0000 Subject: [PATCH 09/53] librustdoc: ignore lint warnings when compiling documentation --- src/librustdoc/core.rs | 1 + src/test/rustdoc/cap-lints.rs | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/test/rustdoc/cap-lints.rs diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4955951d36e84..ae01d6e542611 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -105,6 +105,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, search_paths: search_paths, crate_types: vec!(config::CrateTypeRlib), lint_opts: vec!((warning_lint, lint::Allow)), + lint_cap: Some(lint::Allow), externs: externs, target_triple: triple.unwrap_or(config::host_triple().to_string()), cfg: config::parse_cfgspecs(cfgs), diff --git a/src/test/rustdoc/cap-lints.rs b/src/test/rustdoc/cap-lints.rs new file mode 100644 index 0000000000000..e7f308a6f0b69 --- /dev/null +++ b/src/test/rustdoc/cap-lints.rs @@ -0,0 +1,20 @@ +// 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. + +// This should fail a normal compile due to non_camel_case_types, +// It should pass a doc-compile as it only needs to type-check and +// therefore should not concern itself with the lints. +#[deny(warnings)] + +// @has cap_lints/struct.foo.html //pre '#[must_use]' +#[must_use] +pub struct foo { + field: i32, +} From 900f36fde3c8cc78db1d889e9543aa522cd326da Mon Sep 17 00:00:00 2001 From: Amit Saha Date: Tue, 3 Nov 2015 10:50:20 +1100 Subject: [PATCH 10/53] Specify Microsoft Windows and Mac OS X explicitly When referring to the different shared library extensions, specify the OS explicitly. --- src/doc/trpl/rust-inside-other-languages.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/doc/trpl/rust-inside-other-languages.md b/src/doc/trpl/rust-inside-other-languages.md index 5c0bde02f9605..61627c0b5a2fe 100644 --- a/src/doc/trpl/rust-inside-other-languages.md +++ b/src/doc/trpl/rust-inside-other-languages.md @@ -177,7 +177,8 @@ build deps examples libembed.so native That `libembed.so` is our ‘shared object’ library. We can use this file just like any shared object library written in C! As an aside, this may be -`embed.dll` or `libembed.dylib`, depending on the platform. +`embed.dll` (Microsoft Windows) or `libembed.dylib` (Mac OS X), depending on +your operating system. Now that we’ve got our Rust library built, let’s use it from our Ruby. From 6d7c66e6e82229134fcc5a2b5a23545f8a17f1ce Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 15:46:30 -0400 Subject: [PATCH 11/53] Introduce a "liberated fn sigs" map so that we have easy access to this information when constructing MIR. --- src/librustc/middle/ty/context.rs | 8 ++++++++ src/librustc_typeck/check/mod.rs | 19 ++---------------- src/librustc_typeck/check/regionck.rs | 27 +++++++++++++++++++------- src/librustc_typeck/check/writeback.rs | 23 ++++++++++++++++++++++ 4 files changed, 53 insertions(+), 24 deletions(-) diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 830232cf373b8..a8f045074bd72 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -121,6 +121,13 @@ pub struct Tables<'tcx> { /// Records the type of each closure. The def ID is the ID of the /// expression defining the closure. pub closure_kinds: DefIdMap, + + /// For each fn, records the "liberated" types of its arguments + /// and return type. Liberated means that all bound regions + /// (including late-bound regions) are replaced with free + /// equivalents. This table is not used in trans (since regions + /// are erased there) and hence is not serialized to metadata. + pub liberated_fn_sigs: NodeMap>, } impl<'tcx> Tables<'tcx> { @@ -133,6 +140,7 @@ impl<'tcx> Tables<'tcx> { upvar_capture_map: FnvHashMap(), closure_tys: DefIdMap(), closure_kinds: DefIdMap(), + liberated_fn_sigs: NodeMap(), } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index f085ce23e3f0c..dc2b2b75ab6d1 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -164,11 +164,6 @@ pub struct Inherited<'a, 'tcx: 'a> { tables: &'a RefCell>, - // A mapping from each fn's id to its signature, with all bound - // regions replaced with free ones. Unlike the other tables, this - // one is never copied into the tcx: it is only used by regionck. - fn_sig_map: RefCell>>>, - // When we process a call like `c()` where `c` is a closure type, // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or // `FnOnce` closure. In that case, we defer full resolution of the @@ -314,7 +309,6 @@ impl<'a, 'tcx> Inherited<'a, 'tcx> { infcx: infer::new_infer_ctxt(tcx, tables, Some(param_env), true), locals: RefCell::new(NodeMap()), tables: tables, - fn_sig_map: RefCell::new(NodeMap()), deferred_call_resolutions: RefCell::new(DefIdMap()), deferred_cast_checks: RefCell::new(Vec::new()), } @@ -620,22 +614,13 @@ fn check_fn<'a, 'tcx>(ccx: &'a CrateCtxt<'a, 'tcx>, ccx: ccx }; - // Remember return type so that regionck can access it later. - let mut fn_sig_tys: Vec = - arg_tys.iter() - .cloned() - .collect(); - if let ty::FnConverging(ret_ty) = ret_ty { fcx.require_type_is_sized(ret_ty, decl.output.span(), traits::ReturnType); - fn_sig_tys.push(ret_ty); // FIXME(#25759) just take implied bounds from the arguments } - debug!("fn-sig-map: fn_id={} fn_sig_tys={:?}", - fn_id, - fn_sig_tys); + debug!("fn-sig-map: fn_id={} fn_sig={:?}", fn_id, fn_sig); - inherited.fn_sig_map.borrow_mut().insert(fn_id, fn_sig_tys); + inherited.tables.borrow_mut().liberated_fn_sigs.insert(fn_id, fn_sig.clone()); { let mut visit = GatherLocalsVisitor { fcx: &fcx, }; diff --git a/src/librustc_typeck/check/regionck.rs b/src/librustc_typeck/check/regionck.rs index 6e60f926b7cc9..3cdc9b559446e 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/src/librustc_typeck/check/regionck.rs @@ -284,19 +284,32 @@ impl<'a, 'tcx> Rcx<'a, 'tcx> { // When we enter a function, we can derive debug!("visit_fn_body(id={})", id); - let fn_sig_map = self.fcx.inh.fn_sig_map.borrow(); - let fn_sig = match fn_sig_map.get(&id) { - Some(f) => f, - None => { - self.tcx().sess.bug( - &format!("No fn-sig entry for id={}", id)); + let fn_sig = { + let fn_sig_map = &self.infcx().tables.borrow().liberated_fn_sigs; + match fn_sig_map.get(&id) { + Some(f) => f.clone(), + None => { + self.tcx().sess.bug( + &format!("No fn-sig entry for id={}", id)); + } } }; let old_region_bounds_pairs_len = self.region_bound_pairs.len(); + // Collect the types from which we create inferred bounds. + // For the return type, if diverging, substitute `bool` just + // because it will have no effect. + // + // FIXME(#25759) return types should not be implied bounds + let fn_sig_tys: Vec<_> = + fn_sig.inputs.iter() + .cloned() + .chain(Some(fn_sig.output.unwrap_or(self.tcx().types.bool))) + .collect(); + let old_body_id = self.set_body_id(body.id); - self.relate_free_regions(&fn_sig[..], body.id, span); + self.relate_free_regions(&fn_sig_tys[..], body.id, span); link_fn_args(self, self.tcx().region_maps.node_extent(body.id), &fn_decl.inputs[..]); diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index 2c18a245159cf..cfab28f923e09 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -43,6 +43,7 @@ pub fn resolve_type_vars_in_expr(fcx: &FnCtxt, e: &hir::Expr) { wbcx.visit_expr(e); wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); + wbcx.visit_liberated_fn_sigs(); } pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, @@ -63,6 +64,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, } wbcx.visit_upvar_borrow_map(); wbcx.visit_closures(); + wbcx.visit_liberated_fn_sigs(); } /////////////////////////////////////////////////////////////////////////// @@ -361,6 +363,13 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { } } + fn visit_liberated_fn_sigs(&self) { + for (&node_id, fn_sig) in self.fcx.inh.tables.borrow().liberated_fn_sigs.iter() { + let fn_sig = self.resolve(fn_sig, ResolvingFnSig(node_id)); + self.tcx().tables.borrow_mut().liberated_fn_sigs.insert(node_id, fn_sig.clone()); + } + } + fn resolve>(&self, t: &T, reason: ResolveReason) -> T { t.fold_with(&mut Resolver::new(self.fcx, reason)) } @@ -376,6 +385,7 @@ enum ResolveReason { ResolvingPattern(Span), ResolvingUpvar(ty::UpvarId), ResolvingClosure(DefId), + ResolvingFnSig(ast::NodeId), } impl ResolveReason { @@ -387,6 +397,9 @@ impl ResolveReason { ResolvingUpvar(upvar_id) => { tcx.expr_span(upvar_id.closure_expr_id) } + ResolvingFnSig(id) => { + tcx.map.span(id) + } ResolvingClosure(did) => { if let Some(node_id) = tcx.map.as_local_node_id(did) { tcx.expr_span(node_id) @@ -463,6 +476,16 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { span_err!(self.tcx.sess, span, E0196, "cannot determine a type for this closure") } + + ResolvingFnSig(id) => { + // any failures here should also fail when + // resolving the patterns, closure types, or + // something else. + let span = self.reason.span(self.tcx); + self.tcx.sess.delay_span_bug( + span, + &format!("cannot resolve some aspect of fn sig for {:?}", id)); + } } } } From 88a9c3e764d7938ecbc9c25e840cb60dbd70d170 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:14:25 -0400 Subject: [PATCH 12/53] Build the MIR using the liberated fn sigs, and track the return type --- src/librustc_mir/build/mod.rs | 18 ++++++----- src/librustc_mir/mir_map.rs | 56 ++++++++++++++++++++++------------- src/librustc_mir/repr.rs | 4 ++- 3 files changed, 49 insertions(+), 29 deletions(-) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 857540e2109c0..8e1f08775156e 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -10,7 +10,7 @@ use hair; use rustc::middle::region::CodeExtent; -use rustc::middle::ty::Ty; +use rustc::middle::ty::{FnOutput, Ty}; use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir; use repr::*; @@ -75,13 +75,14 @@ macro_rules! unpack { /////////////////////////////////////////////////////////////////////////// // construct() -- the main entry point for building MIR for a function -pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>, - _span: Span, - implicit_arguments: Vec>, - explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>, - argument_extent: CodeExtent, - ast_block: &'tcx hir::Block) - -> Mir<'tcx> { +pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>, + _span: Span, + implicit_arguments: Vec>, + explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>, + argument_extent: CodeExtent, + return_ty: FnOutput<'tcx>, + ast_block: &'tcx hir::Block) + -> Mir<'tcx> { let cfg = CFG { basic_blocks: vec![] }; // it's handy to have a temporary of type `()` sometimes, so make @@ -121,6 +122,7 @@ pub fn construct<'a, 'tcx>(mut hir: Cx<'a, 'tcx>, var_decls: builder.var_decls, arg_decls: arg_decls, temp_decls: builder.temp_decls, + return_ty: return_ty, } } diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 1acbc8d733d5c..555f8896b4bc5 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -189,26 +189,42 @@ impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> { } } -fn build_mir<'a, 'tcx: 'a>(cx: Cx<'a, 'tcx>, - implicit_arg_tys: Vec>, - fn_id: ast::NodeId, - span: Span, - decl: &'tcx hir::FnDecl, - body: &'tcx hir::Block) - -> Result, ErrorReported> { - let arguments = decl.inputs - .iter() - .map(|arg| { - let ty = cx.tcx().node_id_to_type(arg.id); - (ty, PatNode::irrefutable(&arg.pat)) - }) - .collect(); - - let parameter_scope = cx.tcx().region_maps.lookup_code_extent(CodeExtentData::ParameterScope { - fn_id: fn_id, - body_id: body.id, - }); - Ok(build::construct(cx, span, implicit_arg_tys, arguments, parameter_scope, body)) +fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>, + implicit_arg_tys: Vec>, + fn_id: ast::NodeId, + span: Span, + decl: &'tcx hir::FnDecl, + body: &'tcx hir::Block) + -> Result, ErrorReported> { + // fetch the fully liberated fn signature (that is, all bound + // types/lifetimes replaced) + let fn_sig = match cx.tcx().tables.borrow().liberated_fn_sigs.get(&fn_id) { + Some(f) => f.clone(), + None => { + cx.tcx().sess.span_bug(span, + &format!("no liberated fn sig for {:?}", fn_id)); + } + }; + + let arguments = + decl.inputs + .iter() + .enumerate() + .map(|(index, arg)| { + (fn_sig.inputs[index], PatNode::irrefutable(&arg.pat)) + }) + .collect(); + + let parameter_scope = + cx.tcx().region_maps.lookup_code_extent( + CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id }); + Ok(build::construct(cx, + span, + implicit_arg_tys, + arguments, + parameter_scope, + fn_sig.output, + body)) } fn closure_self_ty<'a, 'tcx>(tcx: &ty::ctxt<'tcx>, diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index 5059955c5dc33..09f174e2ba694 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -12,7 +12,7 @@ use rustc::middle::const_eval::ConstVal; use rustc::middle::def_id::DefId; use rustc::middle::region::CodeExtent; use rustc::middle::subst::Substs; -use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty}; +use rustc::middle::ty::{AdtDef, ClosureSubsts, FnOutput, Region, Ty}; use rustc_back::slice; use rustc_data_structures::fnv::FnvHashMap; use rustc_front::hir::InlineAsm; @@ -25,6 +25,8 @@ use std::u32; pub struct Mir<'tcx> { pub basic_blocks: Vec>, + pub return_ty: FnOutput<'tcx>, + // for every node id pub extents: FnvHashMap>, From 1e30f3e52be35c8992ae882a38b9c74e6adbfef6 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:16:11 -0400 Subject: [PATCH 13/53] Change ShallowDrop to Free, so that it matches what trans will do --- src/librustc_mir/build/expr/as_rvalue.rs | 2 +- src/librustc_mir/repr.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index 3cfc51ec3c98a..c5831b881abe5 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -71,7 +71,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { // schedule a shallow free of that memory, lest we unwind: let extent = this.extent_of_innermost_scope().unwrap(); - this.schedule_drop(expr_span, extent, DropKind::Shallow, &result, value_ty); + this.schedule_drop(expr_span, extent, DropKind::Free, &result, value_ty); // initialize the box contents: let contents = result.clone().deref(); diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index 09f174e2ba694..54e00dc0a68ad 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -355,8 +355,8 @@ pub enum StatementKind<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum DropKind { - Shallow, - Deep, + Free, // free a partially constructed box, should go away eventually + Deep } impl<'tcx> Debug for Statement<'tcx> { @@ -364,7 +364,7 @@ impl<'tcx> Debug for Statement<'tcx> { use self::StatementKind::*; match self.kind { Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv), - Drop(DropKind::Shallow, ref lv) => write!(fmt, "shallow_drop {:?}", lv), + Drop(DropKind::Free, ref lv) => write!(fmt, "free {:?}", lv), Drop(DropKind::Deep, ref lv) => write!(fmt, "drop {:?}", lv), } } From 15c1da4e27587951a8806b6485a8051103019a02 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:19:02 -0400 Subject: [PATCH 14/53] Convert from using named fields to always using indices --- src/librustc/middle/ty/mod.rs | 7 +++++++ src/librustc_mir/build/expr/as_rvalue.rs | 9 ++++++--- src/librustc_mir/repr.rs | 21 ++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/librustc/middle/ty/mod.rs b/src/librustc/middle/ty/mod.rs index 573634414932b..aa18974470178 100644 --- a/src/librustc/middle/ty/mod.rs +++ b/src/librustc/middle/ty/mod.rs @@ -1731,6 +1731,13 @@ impl<'tcx, 'container> VariantDefData<'tcx, 'container> { self.fields.iter().find(|f| f.name == name) } + #[inline] + pub fn index_of_field_named(&self, + name: ast::Name) + -> Option { + self.fields.iter().position(|f| f.name == name) + } + #[inline] pub fn field_named(&self, name: ast::Name) -> &FieldDefData<'tcx, 'container> { self.find_field_named(name).unwrap() diff --git a/src/librustc_mir/build/expr/as_rvalue.rs b/src/librustc_mir/build/expr/as_rvalue.rs index c5831b881abe5..23ca22129fdc0 100644 --- a/src/librustc_mir/build/expr/as_rvalue.rs +++ b/src/librustc_mir/build/expr/as_rvalue.rs @@ -149,16 +149,19 @@ impl<'a,'tcx> Builder<'a,'tcx> { block.and(Rvalue::Aggregate(AggregateKind::Closure(closure_id, substs), upvars)) } ExprKind::Adt { adt_def, variant_index, substs, fields, base } => { // see (*) above - // first process the set of fields + // first process the set of fields that were provided + // (evaluating them in order given by user) let fields_map: FnvHashMap<_, _> = fields.into_iter() .map(|f| (f.name, unpack!(block = this.as_operand(block, f.expr)))) .collect(); - let field_names = this.hir.fields(adt_def, variant_index); - + // if base expression is given, evaluate it now let base = base.map(|base| unpack!(block = this.as_lvalue(block, base))); + // get list of all fields that we will need + let field_names = this.hir.all_fields(adt_def, variant_index); + // for the actual values we use, take either the // expr the user specified or, if they didn't // specify something for this field name, create a diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index 54e00dc0a68ad..5bf326ba5a5fe 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -443,10 +443,19 @@ pub type LvalueProjection<'tcx> = pub type LvalueElem<'tcx> = ProjectionElem<'tcx,Operand<'tcx>>; +/// Index into the list of fields found in a `VariantDef` #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub enum Field { - Named(Name), - Indexed(usize), +pub struct Field(u32); + +impl Field { + pub fn new(value: usize) -> Field { + assert!(value < (u32::MAX) as usize); + Field(value as u32) + } + + pub fn index(self) -> usize { + self.0 as usize + } } impl<'tcx> Lvalue<'tcx> { @@ -491,10 +500,8 @@ impl<'tcx> Debug for Lvalue<'tcx> { write!(fmt,"({:?} as {:?})", data.base, variant_index), ProjectionElem::Deref => write!(fmt,"(*{:?})", data.base), - ProjectionElem::Field(Field::Named(name)) => - write!(fmt,"{:?}.{:?}", data.base, name), - ProjectionElem::Field(Field::Indexed(index)) => - write!(fmt,"{:?}.{:?}", data.base, index), + ProjectionElem::Field(field) => + write!(fmt,"{:?}.{:?}", data.base, field.index()), ProjectionElem::Index(ref index) => write!(fmt,"{:?}[{:?}]", data.base, index), ProjectionElem::ConstantIndex { offset, min_length, from_end: false } => From 3c07b4611815d4d593fba22aaaa975ed97818919 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:20:00 -0400 Subject: [PATCH 15/53] Pass the mir map to trans --- mk/crates.mk | 2 +- src/librustc_driver/driver.rs | 27 +++++++++++++--------- src/librustc_driver/pretty.rs | 4 ++-- src/librustc_trans/lib.rs | 2 ++ src/librustc_trans/trans/base.rs | 7 +++++- src/librustc_trans/trans/context.rs | 8 +++++++ src/librustdoc/core.rs | 2 +- src/test/run-make/execution-engine/test.rs | 4 ++-- 8 files changed, 38 insertions(+), 18 deletions(-) diff --git a/mk/crates.mk b/mk/crates.mk index 6673b9b28e716..2a627a6da2bd6 100644 --- a/mk/crates.mk +++ b/mk/crates.mk @@ -103,7 +103,7 @@ DEPS_rustc_mir := rustc rustc_front syntax DEPS_rustc_resolve := rustc rustc_front log syntax DEPS_rustc_platform_intrinsics := rustc rustc_llvm DEPS_rustc_privacy := rustc rustc_front log syntax -DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \ +DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back rustc_mir \ log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 69c4dcb0a197c..06708a5127f34 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -11,6 +11,7 @@ use rustc::front; use rustc::front::map as hir_map; use rustc_mir as mir; +use rustc_mir::mir_map::MirMap; use rustc::session::Session; use rustc::session::config::{self, Input, OutputFilenames, OutputType}; use rustc::session::search_paths::PathKind; @@ -22,6 +23,7 @@ use rustc::middle::dependency_format; use rustc::middle; use rustc::plugin::registry::Registry; use rustc::plugin; +use rustc::util::nodemap::NodeMap; use rustc::util::common::time; use rustc_borrowck as borrowck; use rustc_resolve as resolve; @@ -146,7 +148,7 @@ pub fn compile_input(sess: Session, &arenas, &id, control.make_glob_map, - |tcx, analysis| { + |tcx, mir_map, analysis| { { let state = CompileState::state_after_analysis(input, @@ -170,7 +172,7 @@ pub fn compile_input(sess: Session, println!("Pre-trans"); tcx.print_debug_stats(); } - let trans = phase_4_translate_to_llvm(tcx, analysis); + let trans = phase_4_translate_to_llvm(tcx, &mir_map, analysis); if log_enabled!(::log::INFO) { println!("Post-trans"); @@ -670,6 +672,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, f: F) -> R where F: for<'a> FnOnce(&'a ty::ctxt<'tcx>, + MirMap<'tcx>, ty::CrateAnalysis) -> R { let time_passes = sess.time_passes(); @@ -751,18 +754,18 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, time(time_passes, "match checking", || middle::check_match::check_crate(tcx)); - match tcx.sess.opts.unstable_features { + let mir_map = match tcx.sess.opts.unstable_features { UnstableFeatures::Disallow => { // use this as a shorthand for beta/stable, and skip // MIR construction there until known regressions are // addressed + NodeMap() } UnstableFeatures::Allow | UnstableFeatures::Cheat => { - let _mir_map = - time(time_passes, "MIR dump", || - mir::mir_map::build_mir_for_crate(tcx)); + time(time_passes, "MIR dump", || + mir::mir_map::build_mir_for_crate(tcx)) } - } + }; time(time_passes, "liveness checking", || middle::liveness::check_crate(tcx)); @@ -804,7 +807,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, // The above three passes generate errors w/o aborting tcx.sess.abort_if_errors(); - f(tcx, ty::CrateAnalysis { + f(tcx, mir_map, ty::CrateAnalysis { export_map: export_map, exported_items: exported_items, public_items: public_items, @@ -817,8 +820,10 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, /// Run the translation phase to LLVM, after which the AST and analysis can /// be discarded. -pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) - -> trans::CrateTranslation { +pub fn phase_4_translate_to_llvm<'tcx>(tcx: &ty::ctxt<'tcx>, + mir_map: &MirMap<'tcx>, + analysis: ty::CrateAnalysis) + -> trans::CrateTranslation { let time_passes = tcx.sess.time_passes(); time(time_passes, "resolving dependency formats", || @@ -826,7 +831,7 @@ pub fn phase_4_translate_to_llvm(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) // Option dance to work around the lack of stack once closures. time(time_passes, "translation", move || - trans::trans_crate(tcx, analysis)) + trans::trans_crate(tcx, mir_map, analysis)) } /// Run LLVM itself, producing a bitcode file, assembly file or object file diff --git a/src/librustc_driver/pretty.rs b/src/librustc_driver/pretty.rs index a30c437197c3b..f53822d2400b4 100644 --- a/src/librustc_driver/pretty.rs +++ b/src/librustc_driver/pretty.rs @@ -182,7 +182,7 @@ impl PpSourceMode { arenas, id, resolve::MakeGlobMap::No, - |tcx, _| { + |tcx, _, _| { let annotation = TypedAnnotation { tcx: tcx }; f(&annotation, payload, &ast_map.forest.krate) }) @@ -782,7 +782,7 @@ pub fn pretty_print_input(sess: Session, &arenas, &id, resolve::MakeGlobMap::No, - |tcx, _| { + |tcx, _, _| { print_flowgraph(variants, tcx, code, mode, out) }) } diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index e02ce49132a7c..bc5b6f6b9d7d9 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -37,6 +37,7 @@ #![feature(quote)] #![feature(rustc_diagnostic_macros)] #![feature(rustc_private)] +#![feature(slice_patterns)] #![feature(staged_api)] #![feature(unicode)] #![feature(vec_push_all)] @@ -52,6 +53,7 @@ extern crate rustc; extern crate rustc_back; extern crate rustc_front; extern crate rustc_llvm as llvm; +extern crate rustc_mir; extern crate rustc_platform_intrinsics as intrinsics; extern crate serialize; diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 46a4cb0c92ee7..f28b7e8f52dc3 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -44,6 +44,7 @@ use middle::pat_util::simple_name; use middle::subst::Substs; use middle::ty::{self, Ty, HasTypeFlags}; use rustc::front::map as hir_map; +use rustc_mir::mir_map::MirMap; use session::config::{self, NoDebugInfo, FullDebugInfo}; use session::Session; use trans::_match; @@ -2737,7 +2738,10 @@ pub fn filter_reachable_ids(ccx: &SharedCrateContext) -> NodeSet { }).collect() } -pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslation { +pub fn trans_crate<'tcx>(tcx: &ty::ctxt<'tcx>, + mir_map: &MirMap<'tcx>, + analysis: ty::CrateAnalysis) + -> CrateTranslation { let ty::CrateAnalysis { export_map, reachable, name, .. } = analysis; let krate = tcx.map.krate(); @@ -2779,6 +2783,7 @@ pub fn trans_crate(tcx: &ty::ctxt, analysis: ty::CrateAnalysis) -> CrateTranslat let shared_ccx = SharedCrateContext::new(&link_meta.crate_name, codegen_units, tcx, + &mir_map, export_map, Sha256::new(), link_meta.clone(), diff --git a/src/librustc_trans/trans/context.rs b/src/librustc_trans/trans/context.rs index 01d0c51a08dd9..1f1d43feeb38e 100644 --- a/src/librustc_trans/trans/context.rs +++ b/src/librustc_trans/trans/context.rs @@ -14,6 +14,7 @@ use metadata::common::LinkMeta; use middle::def::ExportMap; use middle::def_id::DefId; use middle::traits; +use rustc_mir::mir_map::MirMap; use trans::adt; use trans::base; use trans::builder::Builder; @@ -70,6 +71,7 @@ pub struct SharedCrateContext<'a, 'tcx: 'a> { stats: Stats, check_overflow: bool, check_drop_flag_for_sanity: bool, + mir_map: &'a MirMap<'tcx>, available_drop_glues: RefCell, String>>, use_dll_storage_attrs: bool, @@ -251,6 +253,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { pub fn new(crate_name: &str, local_count: usize, tcx: &'b ty::ctxt<'tcx>, + mir_map: &'b MirMap<'tcx>, export_map: ExportMap, symbol_hasher: Sha256, link_meta: LinkMeta, @@ -317,6 +320,7 @@ impl<'b, 'tcx> SharedCrateContext<'b, 'tcx> { link_meta: link_meta, symbol_hasher: RefCell::new(symbol_hasher), tcx: tcx, + mir_map: mir_map, stats: Stats { n_glues_created: Cell::new(0), n_null_glues: Cell::new(0), @@ -803,6 +807,10 @@ impl<'b, 'tcx> CrateContext<'b, 'tcx> { pub fn use_dll_storage_attrs(&self) -> bool { self.shared.use_dll_storage_attrs() } + + pub fn mir_map(&self) -> &'b MirMap<'tcx> { + self.shared.mir_map + } } pub struct TypeOfDepthLock<'a, 'tcx: 'a>(&'a LocalCrateContext<'tcx>); diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 4955951d36e84..d07d44a2a9412 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -145,7 +145,7 @@ pub fn run_core(search_paths: SearchPaths, cfgs: Vec, externs: Externs, &arenas, &name, resolve::MakeGlobMap::No, - |tcx, analysis| { + |tcx, _, analysis| { let ty::CrateAnalysis { exported_items, public_items, .. } = analysis; // Convert from a NodeId set to a DefId set since we don't always have easy access diff --git a/src/test/run-make/execution-engine/test.rs b/src/test/run-make/execution-engine/test.rs index f4031a3aaae1c..f2dd155595ac4 100644 --- a/src/test/run-make/execution-engine/test.rs +++ b/src/test/run-make/execution-engine/test.rs @@ -229,9 +229,9 @@ fn compile_program(input: &str, sysroot: PathBuf) let ast_map = driver::make_map(&sess, &mut hir_forest); driver::phase_3_run_analysis_passes( - &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, analysis| { + &sess, ast_map, &arenas, &id, MakeGlobMap::No, |tcx, mir_map, analysis| { - let trans = driver::phase_4_translate_to_llvm(tcx, analysis); + let trans = driver::phase_4_translate_to_llvm(tcx, &mir_map, analysis); let crates = tcx.sess.cstore.get_used_crates(RequireDynamic); From b5d358084395b76277d2c92f73c28338f9432a25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:24:05 -0400 Subject: [PATCH 16/53] Move the "HAIR" code that reads the tcx tables etc out of the `tcx` module and into `hair/cx`, now that we don't have a trait defining the interface --- src/librustc_mir/build/mod.rs | 2 +- src/librustc_mir/{tcx => hair/cx}/block.rs | 28 +++------ src/librustc_mir/{tcx => hair/cx}/expr.rs | 60 ++++++++++++++------ src/librustc_mir/{tcx => hair/cx}/mod.rs | 17 ++---- src/librustc_mir/{tcx => hair/cx}/pattern.rs | 37 +++++++++--- src/librustc_mir/{tcx => hair/cx}/to_ref.rs | 14 +---- src/librustc_mir/{hair.rs => hair/mod.rs} | 8 +-- src/librustc_mir/lib.rs | 5 +- src/librustc_mir/mir_map.rs | 2 +- 9 files changed, 94 insertions(+), 79 deletions(-) rename src/librustc_mir/{tcx => hair/cx}/block.rs (82%) rename src/librustc_mir/{tcx => hair/cx}/expr.rs (94%) rename src/librustc_mir/{tcx => hair/cx}/mod.rs (90%) rename src/librustc_mir/{tcx => hair/cx}/pattern.rs (89%) rename src/librustc_mir/{tcx => hair/cx}/to_ref.rs (85%) rename src/librustc_mir/{hair.rs => hair/mod.rs} (98%) diff --git a/src/librustc_mir/build/mod.rs b/src/librustc_mir/build/mod.rs index 8e1f08775156e..56a20167b7942 100644 --- a/src/librustc_mir/build/mod.rs +++ b/src/librustc_mir/build/mod.rs @@ -9,6 +9,7 @@ // except according to those terms. use hair; +use hair::cx::{Cx, PatNode}; use rustc::middle::region::CodeExtent; use rustc::middle::ty::{FnOutput, Ty}; use rustc_data_structures::fnv::FnvHashMap; @@ -16,7 +17,6 @@ use rustc_front::hir; use repr::*; use syntax::ast; use syntax::codemap::Span; -use tcx::{Cx, PatNode}; struct Builder<'a, 'tcx: 'a> { hir: Cx<'a, 'tcx>, diff --git a/src/librustc_mir/tcx/block.rs b/src/librustc_mir/hair/cx/block.rs similarity index 82% rename from src/librustc_mir/tcx/block.rs rename to src/librustc_mir/hair/cx/block.rs index dc168bc7c2b6c..a407c42372a81 100644 --- a/src/librustc_mir/tcx/block.rs +++ b/src/librustc_mir/hair/cx/block.rs @@ -9,10 +9,9 @@ // except according to those terms. use hair::*; - -use tcx::Cx; -use tcx::pattern::PatNode; -use tcx::to_ref::ToRef; +use hair::cx::Cx; +use hair::cx::pattern::PatNode; +use hair::cx::to_ref::ToRef; use rustc::middle::region::{BlockRemainder, CodeExtentData}; use rustc_front::hir; use syntax::ast; @@ -34,22 +33,11 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Block { } } -impl<'tcx> Mirror<'tcx> for &'tcx hir::Stmt { - type Output = Stmt<'tcx>; - - fn make_mirror<'a>(self, _cx: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> { - // In order to get the scoping correct, we eagerly mirror - // statements when we translate the enclosing block, so we - // should in fact never get to this point. - panic!("statements are eagerly mirrored"); - } -} - -fn mirror_stmts<'a, 'tcx: 'a, STMTS>(cx: &mut Cx<'a, 'tcx>, - block_id: ast::NodeId, - mut stmts: STMTS) - -> Vec> - where STMTS: Iterator)> +fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>, + block_id: ast::NodeId, + mut stmts: STMTS) + -> Vec> + where STMTS: Iterator)> { let mut result = vec![]; while let Some((index, stmt)) = stmts.next() { diff --git a/src/librustc_mir/tcx/expr.rs b/src/librustc_mir/hair/cx/expr.rs similarity index 94% rename from src/librustc_mir/tcx/expr.rs rename to src/librustc_mir/hair/cx/expr.rs index 9f7ecf522876f..847d76f7d17a9 100644 --- a/src/librustc_mir/tcx/expr.rs +++ b/src/librustc_mir/hair/cx/expr.rs @@ -12,16 +12,16 @@ use hair::*; use repr::*; use rustc_data_structures::fnv::FnvHashMap; use std::rc::Rc; -use tcx::Cx; -use tcx::block; -use tcx::pattern::PatNode; -use tcx::to_ref::ToRef; +use hair::cx::Cx; +use hair::cx::block; +use hair::cx::pattern::PatNode; +use hair::cx::to_ref::ToRef; use rustc::front::map; use rustc::middle::const_eval; use rustc::middle::def; use rustc::middle::region::CodeExtent; use rustc::middle::pat_util; -use rustc::middle::ty::{self, Ty}; +use rustc::middle::ty::{self, VariantDef, Ty}; use rustc_front::hir; use rustc_front::util as hir_util; use syntax::parse::token; @@ -170,11 +170,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { hir::ExprStruct(_, ref fields, ref base) => { match expr_ty.sty { ty::TyStruct(adt, substs) => { + let field_refs = field_refs(&adt.variants[0], fields); ExprKind::Adt { adt_def: adt, variant_index: 0, substs: substs, - fields: fields.to_ref(), + fields: field_refs, base: base.to_ref(), } } @@ -183,11 +184,12 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { def::DefVariant(enum_id, variant_id, true) => { debug_assert!(adt.did == enum_id); let index = adt.variant_index_with_id(variant_id); + let field_refs = field_refs(&adt.variants[index], fields); ExprKind::Adt { adt_def: adt, variant_index: index, substs: substs, - fields: fields.to_ref(), + fields: field_refs, base: base.to_ref(), } } @@ -238,11 +240,10 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { } }; - let field_expr_ref = |s: &'tcx P, nm: &str| { - FieldExprRef { - name: Field::Named(token::intern(nm)), - expr: s.to_ref(), - } + let field_expr_ref = |s: &'tcx P, name: &str| { + let name = token::intern(name); + let index = adt_def.variants[0].index_of_field_named(name).unwrap(); + FieldExprRef { name: Field::new(index), expr: s.to_ref() } }; let start_field = start.as_ref() @@ -293,12 +294,25 @@ impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr { hir::ExprLoop(ref body, _) => ExprKind::Loop { condition: None, body: block::to_expr_ref(cx, body) }, - hir::ExprField(ref source, name) => - ExprKind::Field { lhs: source.to_ref(), - name: Field::Named(name.node) }, + hir::ExprField(ref source, name) => { + let index = match cx.tcx.expr_ty_adjusted(source).sty { + ty::TyStruct(adt_def, _) => + adt_def.variants[0].index_of_field_named(name.node), + ref ty => + cx.tcx.sess.span_bug( + self.span, + &format!("field of non-struct: {:?}", ty)), + }; + let index = index.unwrap_or_else(|| { + cx.tcx.sess.span_bug( + self.span, + &format!("no index found for field `{}`", name.node)); + }); + ExprKind::Field { lhs: source.to_ref(), name: Field::new(index) } + } hir::ExprTupField(ref source, index) => ExprKind::Field { lhs: source.to_ref(), - name: Field::Indexed(index.node) }, + name: Field::new(index.node as usize) }, hir::ExprCast(ref source, _) => ExprKind::Cast { source: source.to_ref() }, hir::ExprBox(ref value) => @@ -616,7 +630,7 @@ fn convert_var<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, // at this point we have `self.n`, which loads up the upvar let field_kind = ExprKind::Field { lhs: self_expr.to_ref(), - name: Field::Indexed(index), + name: Field::new(index), }; // ...but the upvar might be an `&T` or `&mut T` capture, at which @@ -814,3 +828,15 @@ fn loop_label<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, expr: &'tcx hir::Expr) -> Cod } } } + +fn field_refs<'tcx>(variant: VariantDef<'tcx>, + fields: &'tcx [hir::Field]) + -> Vec> +{ + fields.iter() + .map(|field| FieldExprRef { + name: Field::new(variant.index_of_field_named(field.name.node).unwrap()), + expr: field.expr.to_ref(), + }) + .collect() +} diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/hair/cx/mod.rs similarity index 90% rename from src/librustc_mir/tcx/mod.rs rename to src/librustc_mir/hair/cx/mod.rs index 92b026e5035b4..8d4b05afcb6e6 100644 --- a/src/librustc_mir/tcx/mod.rs +++ b/src/librustc_mir/hair/cx/mod.rs @@ -24,7 +24,7 @@ use rustc::middle::infer::InferCtxt; use rustc::middle::subst::{Subst, Substs}; use rustc::middle::ty::{self, Ty}; use syntax::codemap::Span; -use syntax::parse::token::{self, special_idents}; +use syntax::parse::token; #[derive(Copy, Clone)] pub struct Cx<'a, 'tcx: 'a> { @@ -87,18 +87,9 @@ impl<'a,'tcx:'a> Cx<'a, 'tcx> { adt_def.variants.len() } - pub fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec { - adt_def.variants[variant_index] - .fields - .iter() - .enumerate() - .map(|(index, field)| { - if field.name == special_idents::unnamed_field.name { - Field::Indexed(index) - } else { - Field::Named(field.name) - } - }) + pub fn all_fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec { + (0..adt_def.variants[variant_index].fields.len()) + .map(Field::new) .collect() } diff --git a/src/librustc_mir/tcx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs similarity index 89% rename from src/librustc_mir/tcx/pattern.rs rename to src/librustc_mir/hair/cx/pattern.rs index db4346364968c..31dbffa0ae348 100644 --- a/src/librustc_mir/tcx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -9,12 +9,11 @@ // except according to those terms. use hair::*; +use hair::cx::Cx; +use hair::cx::to_ref::ToRef; use repr::*; - use rustc_data_structures::fnv::FnvHashMap; use std::rc::Rc; -use tcx::Cx; -use tcx::to_ref::ToRef; use rustc::middle::const_eval; use rustc::middle::def; use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding}; @@ -223,7 +222,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { subpatterns.iter() .enumerate() .map(|(i, subpattern)| FieldPatternRef { - field: Field::Indexed(i), + field: Field::new(i), pattern: self.pat_ref(subpattern), }) .collect(); @@ -273,7 +272,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { .flat_map(|v| v.iter()) .enumerate() .map(|(i, field)| FieldPatternRef { - field: Field::Indexed(i), + field: Field::new(i), pattern: self.pat_ref(field), }) .collect(); @@ -281,13 +280,35 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { } hir::PatStruct(_, ref fields, _) => { + let pat_ty = cx.tcx.node_id_to_type(self.pat.id); + let adt_def = match pat_ty.sty { + ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def, + _ => { + cx.tcx.sess.span_bug( + self.pat.span, + "struct pattern not applied to struct or enum"); + } + }; + + let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def(); + let variant_def = adt_def.variant_of_def(def); + let subpatterns = fields.iter() - .map(|field| FieldPatternRef { - field: Field::Named(field.node.name), - pattern: self.pat_ref(&field.node.pat), + .map(|field| { + let index = variant_def.index_of_field_named(field.node.name); + let index = index.unwrap_or_else(|| { + cx.tcx.sess.span_bug( + self.pat.span, + &format!("no field with name {:?}", field.node.name)); + }); + FieldPatternRef { + field: Field::new(index), + pattern: self.pat_ref(&field.node.pat), + } }) .collect(); + self.variant_or_leaf(cx, subpatterns) } diff --git a/src/librustc_mir/tcx/to_ref.rs b/src/librustc_mir/hair/cx/to_ref.rs similarity index 85% rename from src/librustc_mir/tcx/to_ref.rs rename to src/librustc_mir/hair/cx/to_ref.rs index 13ca82e3e4c71..e0b8abfbd9ce3 100644 --- a/src/librustc_mir/tcx/to_ref.rs +++ b/src/librustc_mir/hair/cx/to_ref.rs @@ -9,9 +9,8 @@ // except according to those terms. use hair::*; -use repr::*; -use tcx::pattern::PatNode; +use hair::cx::pattern::PatNode; use rustc_front::hir; use syntax::ptr::P; @@ -79,14 +78,3 @@ impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec self.iter().map(|expr| expr.to_ref()).collect() } } - -impl<'a,'tcx:'a> ToRef for &'tcx hir::Field { - type Output = FieldExprRef<'tcx>; - - fn to_ref(self) -> FieldExprRef<'tcx> { - FieldExprRef { - name: Field::Named(self.name.node), - expr: self.expr.to_ref(), - } - } -} diff --git a/src/librustc_mir/hair.rs b/src/librustc_mir/hair/mod.rs similarity index 98% rename from src/librustc_mir/hair.rs rename to src/librustc_mir/hair/mod.rs index 641cbae4be271..becaa19974d8e 100644 --- a/src/librustc_mir/hair.rs +++ b/src/librustc_mir/hair/mod.rs @@ -22,7 +22,9 @@ use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty}; use rustc_front::hir; use syntax::ast; use syntax::codemap::Span; -use tcx::{Cx, PatNode}; +use self::cx::{Cx, PatNode}; + +pub mod cx; #[derive(Clone, Debug)] pub struct ItemRef<'tcx> { @@ -41,7 +43,6 @@ pub struct Block<'tcx> { #[derive(Clone, Debug)] pub enum StmtRef<'tcx> { - Hair(&'tcx hir::Stmt), Mirror(Box>), } @@ -392,9 +393,8 @@ impl<'tcx> Mirror<'tcx> for Stmt<'tcx> { impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> { type Output = Stmt<'tcx>; - fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Stmt<'tcx> { + fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Stmt<'tcx> { match self { - StmtRef::Hair(h) => h.make_mirror(hir), StmtRef::Mirror(m) => *m, } } diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 934dd660177b8..215f708cadd0c 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -31,7 +31,8 @@ extern crate syntax; pub mod build; pub mod mir_map; -pub mod hair; +mod hair; pub mod repr; mod graphviz; -mod tcx; + + diff --git a/src/librustc_mir/mir_map.rs b/src/librustc_mir/mir_map.rs index 555f8896b4bc5..ebcb1db1151ee 100644 --- a/src/librustc_mir/mir_map.rs +++ b/src/librustc_mir/mir_map.rs @@ -23,8 +23,8 @@ extern crate rustc_front; use build; use dot; use repr::Mir; +use hair::cx::{PatNode, Cx}; use std::fs::File; -use tcx::{PatNode, Cx}; use self::rustc::middle::infer; use self::rustc::middle::region::CodeExtentData; From 3ab29d337834383c159b2a4e275581f97ad34a25 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:28:51 -0400 Subject: [PATCH 17/53] Add adt_def into Switch, since it's convenient to have in trans --- src/librustc_mir/build/matches/test.rs | 1 + src/librustc_mir/repr.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index d5745eb28c7a8..0d01df485fa8a 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -92,6 +92,7 @@ impl<'a,'tcx> Builder<'a,'tcx> { .collect(); self.cfg.terminate(block, Terminator::Switch { discr: lvalue.clone(), + adt_def: adt_def, targets: target_blocks.clone() }); target_blocks diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index 5bf326ba5a5fe..eb919f36cc370 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -247,6 +247,7 @@ pub enum Terminator<'tcx> { /// lvalue evaluates to some enum; jump depending on the branch Switch { discr: Lvalue<'tcx>, + adt_def: AdtDef<'tcx>, targets: Vec, }, @@ -279,7 +280,7 @@ impl<'tcx> Terminator<'tcx> { Goto { target: ref b } => slice::ref_slice(b), Panic { target: ref b } => slice::ref_slice(b), If { cond: _, targets: ref b } => b, - Switch { discr: _, targets: ref b } => b, + Switch { discr: _, adt_def: _, targets: ref b } => b, Diverge => &[], Return => &[], Call { data: _, targets: ref b } => b, @@ -318,7 +319,7 @@ impl<'tcx> Debug for Terminator<'tcx> { write!(fmt, "panic -> {:?}", target), If { cond: ref lv, ref targets } => write!(fmt, "if({:?}) -> {:?}", lv, targets), - Switch { discr: ref lv, ref targets } => + Switch { discr: ref lv, adt_def: _, ref targets } => write!(fmt, "switch({:?}) -> {:?}", lv, targets), Diverge => write!(fmt, "diverge"), From 044096b3e9a8d02461d49fb5559bb11c4308e701 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:29:50 -0400 Subject: [PATCH 18/53] Change Call operands to be, well, Operands --- src/librustc_mir/build/expr/into.rs | 4 ++-- src/librustc_mir/build/matches/test.rs | 19 ++++++++++--------- src/librustc_mir/build/misc.rs | 26 +++++++++++--------------- src/librustc_mir/repr.rs | 4 ++-- 4 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/librustc_mir/build/expr/into.rs b/src/librustc_mir/build/expr/into.rs index a7d68b09b5459..57c6db79c5271 100644 --- a/src/librustc_mir/build/expr/into.rs +++ b/src/librustc_mir/build/expr/into.rs @@ -211,10 +211,10 @@ impl<'a,'tcx> Builder<'a,'tcx> { this.cfg.start_new_block().unit() } ExprKind::Call { fun, args } => { - let fun = unpack!(block = this.as_lvalue(block, fun)); + let fun = unpack!(block = this.as_operand(block, fun)); let args: Vec<_> = args.into_iter() - .map(|arg| unpack!(block = this.as_lvalue(block, arg))) + .map(|arg| unpack!(block = this.as_operand(block, arg))) .collect(); let success = this.cfg.start_new_block(); let panic = this.diverge_cleanup(); diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs index 0d01df485fa8a..e035f53dacf41 100644 --- a/src/librustc_mir/build/matches/test.rs +++ b/src/librustc_mir/build/matches/test.rs @@ -100,27 +100,28 @@ impl<'a,'tcx> Builder<'a,'tcx> { TestKind::Eq { value, ty } => { // call PartialEq::eq(discrim, constant) - let constant = self.push_literal(block, test.span, ty.clone(), value); + let constant = self.literal_operand(test.span, ty.clone(), value); let item_ref = self.hir.partial_eq(ty); - self.call_comparison_fn(block, test.span, item_ref, lvalue.clone(), constant) + self.call_comparison_fn(block, test.span, item_ref, + Operand::Consume(lvalue.clone()), constant) } TestKind::Range { lo, hi, ty } => { // Test `v` by computing `PartialOrd::le(lo, v) && PartialOrd::le(v, hi)`. - let lo = self.push_literal(block, test.span, ty.clone(), lo); - let hi = self.push_literal(block, test.span, ty.clone(), hi); + let lo = self.literal_operand(test.span, ty.clone(), lo); + let hi = self.literal_operand(test.span, ty.clone(), hi); let item_ref = self.hir.partial_le(ty); let lo_blocks = self.call_comparison_fn(block, test.span, item_ref.clone(), lo, - lvalue.clone()); + Operand::Consume(lvalue.clone())); let hi_blocks = self.call_comparison_fn(lo_blocks[0], test.span, item_ref, - lvalue.clone(), + Operand::Consume(lvalue.clone()), hi); let failure = self.cfg.start_new_block(); @@ -165,14 +166,14 @@ impl<'a,'tcx> Builder<'a,'tcx> { block: BasicBlock, span: Span, item_ref: ItemRef<'tcx>, - lvalue1: Lvalue<'tcx>, - lvalue2: Lvalue<'tcx>) + lvalue1: Operand<'tcx>, + lvalue2: Operand<'tcx>) -> Vec { let target_blocks = vec![self.cfg.start_new_block(), self.cfg.start_new_block()]; let bool_ty = self.hir.bool_ty(); let eq_result = self.temp(bool_ty); - let func = self.push_item_ref(block, span, item_ref); + let func = self.item_ref_operand(span, item_ref); let call_blocks = [self.cfg.start_new_block(), self.diverge_cleanup()]; self.cfg.terminate(block, Terminator::Call { diff --git a/src/librustc_mir/build/misc.rs b/src/librustc_mir/build/misc.rs index 86b6df19b77e7..41274f3f3736e 100644 --- a/src/librustc_mir/build/misc.rs +++ b/src/librustc_mir/build/misc.rs @@ -34,20 +34,17 @@ impl<'a,'tcx> Builder<'a,'tcx> { lvalue } - pub fn push_literal(&mut self, - block: BasicBlock, - span: Span, - ty: Ty<'tcx>, - literal: Literal<'tcx>) - -> Lvalue<'tcx> { - let temp = self.temp(ty.clone()); + pub fn literal_operand(&mut self, + span: Span, + ty: Ty<'tcx>, + literal: Literal<'tcx>) + -> Operand<'tcx> { let constant = Constant { span: span, ty: ty, literal: literal, }; - self.cfg.push_assign_constant(block, span, &temp, constant); - temp + Operand::Constant(constant) } pub fn push_usize(&mut self, block: BasicBlock, span: Span, value: usize) -> Lvalue<'tcx> { @@ -63,15 +60,14 @@ impl<'a,'tcx> Builder<'a,'tcx> { temp } - pub fn push_item_ref(&mut self, - block: BasicBlock, - span: Span, - item_ref: ItemRef<'tcx>) - -> Lvalue<'tcx> { + pub fn item_ref_operand(&mut self, + span: Span, + item_ref: ItemRef<'tcx>) + -> Operand<'tcx> { let literal = Literal::Item { def_id: item_ref.def_id, substs: item_ref.substs, }; - self.push_literal(block, span, item_ref.ty, literal) + self.literal_operand(span, item_ref.ty, literal) } } diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs index eb919f36cc370..89b1afa872381 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -294,10 +294,10 @@ pub struct CallData<'tcx> { pub destination: Lvalue<'tcx>, /// the fn being called - pub func: Lvalue<'tcx>, + pub func: Operand<'tcx>, /// the arguments - pub args: Vec>, + pub args: Vec>, } impl<'tcx> BasicBlockData<'tcx> { From 0a62158a4e1bb012d5b0778701dd67b65a8754c2 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:30:17 -0400 Subject: [PATCH 19/53] Add helper methods that require tcx; these compute types of lvalues and operands --- src/librustc_mir/lib.rs | 2 +- src/librustc_mir/tcx/mod.rs | 125 ++++++++++++++++++++++++++++++++++++ 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 src/librustc_mir/tcx/mod.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 215f708cadd0c..5c52dfe2bd673 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -34,5 +34,5 @@ pub mod mir_map; mod hair; pub mod repr; mod graphviz; - +pub mod tcx; diff --git a/src/librustc_mir/tcx/mod.rs b/src/librustc_mir/tcx/mod.rs new file mode 100644 index 0000000000000..3b9d9228a1680 --- /dev/null +++ b/src/librustc_mir/tcx/mod.rs @@ -0,0 +1,125 @@ +// 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. + +/*! + * Methods for the various MIR types. These are intended for use after + * building is complete. + */ + +use repr::*; +use rustc::middle::subst::Substs; +use rustc::middle::ty::{self, AdtDef, Ty}; + +#[derive(Copy, Clone, Debug)] +pub enum LvalueTy<'tcx> { + /// Normal type. + Ty { ty: Ty<'tcx> }, + + /// Downcast to a particular variant of an enum. + Downcast { adt_def: AdtDef<'tcx>, + substs: &'tcx Substs<'tcx>, + variant_index: usize }, +} + +impl<'tcx> LvalueTy<'tcx> { + pub fn from_ty(ty: Ty<'tcx>) -> LvalueTy<'tcx> { + LvalueTy::Ty { ty: ty } + } + + pub fn to_ty(&self, tcx: &ty::ctxt<'tcx>) -> Ty<'tcx> { + match *self { + LvalueTy::Ty { ty } => + ty, + LvalueTy::Downcast { adt_def, substs, variant_index: _ } => + tcx.mk_enum(adt_def, substs), + } + } + + pub fn projection_ty(self, + tcx: &ty::ctxt<'tcx>, + elem: &LvalueElem<'tcx>) + -> LvalueTy<'tcx> + { + match *elem { + ProjectionElem::Deref => + LvalueTy::Ty { + ty: self.to_ty(tcx).builtin_deref(true, ty::LvaluePreference::NoPreference) + .unwrap() + .ty + }, + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => + LvalueTy::Ty { + ty: self.to_ty(tcx).builtin_index().unwrap() + }, + ProjectionElem::Downcast(adt_def1, index) => + match self.to_ty(tcx).sty { + ty::TyEnum(adt_def, substs) => { + assert!(index < adt_def.variants.len()); + assert_eq!(adt_def, adt_def1); + LvalueTy::Downcast { adt_def: adt_def, + substs: substs, + variant_index: index } + } + _ => { + tcx.sess.bug(&format!("cannot downcast non-enum type: `{:?}`", self)) + } + }, + ProjectionElem::Field(field) => { + let field_ty = match self { + LvalueTy::Ty { ty } => match ty.sty { + ty::TyStruct(adt_def, substs) => + adt_def.struct_variant().fields[field.index()].ty(tcx, substs), + ty::TyTuple(ref tys) => + tys[field.index()], + _ => + tcx.sess.bug(&format!("cannot get field of type: `{:?}`", ty)), + }, + LvalueTy::Downcast { adt_def, substs, variant_index } => + adt_def.variants[variant_index].fields[field.index()].ty(tcx, substs), + }; + LvalueTy::Ty { ty: field_ty } + } + } + } +} + +impl<'tcx> Mir<'tcx> { + pub fn operand_ty(&self, + tcx: &ty::ctxt<'tcx>, + operand: &Operand<'tcx>) + -> Ty<'tcx> + { + match *operand { + Operand::Consume(ref l) => self.lvalue_ty(tcx, l).to_ty(tcx), + Operand::Constant(ref c) => c.ty, + } + } + + pub fn lvalue_ty(&self, + tcx: &ty::ctxt<'tcx>, + lvalue: &Lvalue<'tcx>) + -> LvalueTy<'tcx> + { + match *lvalue { + Lvalue::Var(index) => + LvalueTy::Ty { ty: self.var_decls[index as usize].ty }, + Lvalue::Temp(index) => + LvalueTy::Ty { ty: self.temp_decls[index as usize].ty }, + Lvalue::Arg(index) => + LvalueTy::Ty { ty: self.arg_decls[index as usize].ty }, + Lvalue::Static(def_id) => + LvalueTy::Ty { ty: tcx.lookup_item_type(def_id).ty }, + Lvalue::ReturnPointer => + LvalueTy::Ty { ty: self.return_ty.unwrap() }, + Lvalue::Projection(ref proj) => + self.lvalue_ty(tcx, &proj.base).projection_ty(tcx, &proj.elem) + } + } +} From 81ff2c2f8e964c33ac8d4b3570fc881658301068 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:33:08 -0400 Subject: [PATCH 20/53] Change adt case handling fn to be less tied to match --- src/librustc_trans/trans/_match.rs | 2 +- src/librustc_trans/trans/adt.rs | 10 ++++------ src/librustc_trans/trans/base.rs | 9 ++------- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 2654ab3339a10..3c53d55886565 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -303,7 +303,7 @@ impl<'a, 'tcx> Opt<'a, 'tcx> { RangeResult(Result::new(bcx, l1), Result::new(bcx, l2)) } Variant(disr_val, ref repr, _, _) => { - adt::trans_case(bcx, &**repr, disr_val) + SingleResult(Result::new(bcx, adt::trans_case(bcx, &**repr, disr_val))) } SliceLengthEqual(length, _) => { SingleResult(Result::new(bcx, C_uint(ccx, length))) diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs index de09e33ec1427..a4f66110450df 100644 --- a/src/librustc_trans/trans/adt.rs +++ b/src/librustc_trans/trans/adt.rs @@ -945,15 +945,13 @@ fn load_discr(bcx: Block, ity: IntType, ptr: ValueRef, min: Disr, max: Disr) /// /// This should ideally be less tightly tied to `_match`. pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr) - -> _match::OptResult<'blk, 'tcx> { + -> ValueRef { match *r { CEnum(ity, _, _) => { - _match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity), - discr as u64, true))) + C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true) } General(ity, _, _) => { - _match::SingleResult(Result::new(bcx, C_integral(ll_inttype(bcx.ccx(), ity), - discr as u64, true))) + C_integral(ll_inttype(bcx.ccx(), ity), discr as u64, true) } Univariant(..) => { bcx.ccx().sess().bug("no cases for univariants or structs") @@ -961,7 +959,7 @@ pub fn trans_case<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, r: &Repr, discr: Disr) RawNullablePointer { .. } | StructWrappedNullablePointer { .. } => { assert!(discr == 0 || discr == 1); - _match::SingleResult(Result::new(bcx, C_bool(bcx.ccx(), discr != 0))) + C_bool(bcx.ccx(), discr != 0) } } } diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index f28b7e8f52dc3..9530c6d4058ee 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -498,13 +498,8 @@ pub fn iter_structural_ty<'blk, 'tcx, F>(cx: Block<'blk, 'tcx>, &format!("enum-iter-variant-{}", &variant.disr_val.to_string()) ); - match adt::trans_case(cx, &*repr, variant.disr_val) { - _match::SingleResult(r) => { - AddCase(llswitch, r.val, variant_cx.llbb) - } - _ => ccx.sess().unimpl("value from adt::trans_case \ - in iter_structural_ty") - } + let case_val = adt::trans_case(cx, &*repr, variant.disr_val); + AddCase(llswitch, case_val, variant_cx.llbb); let variant_cx = iter_variant(variant_cx, &*repr, From 877b93add2a0d7cc603fa3146a3b9b0af0215e9d Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:35:15 -0400 Subject: [PATCH 21/53] Move shifting code out of expr and into somewhere more accessible --- src/librustc_trans/trans/base.rs | 12 ++++- src/librustc_trans/trans/common.rs | 78 +++++++++++++++++++++++++++++- src/librustc_trans/trans/expr.rs | 61 ----------------------- 3 files changed, 88 insertions(+), 63 deletions(-) diff --git a/src/librustc_trans/trans/base.rs b/src/librustc_trans/trans/base.rs index 9530c6d4058ee..a536060efbd0f 100644 --- a/src/librustc_trans/trans/base.rs +++ b/src/librustc_trans/trans/base.rs @@ -75,6 +75,7 @@ use trans::intrinsic; use trans::machine; use trans::machine::{llsize_of, llsize_of_real}; use trans::meth; +use trans::mir; use trans::monomorphize; use trans::tvec; use trans::type_::Type; @@ -1231,7 +1232,10 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>, false }; + let mir = ccx.mir_map().get(&id); + let mut fcx = FunctionContext { + mir: mir, llfn: llfndecl, llenv: None, llretslotptr: Cell::new(None), @@ -1571,7 +1575,7 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, llfndecl: ValueRef, param_substs: &'tcx Substs<'tcx>, fn_ast_id: ast::NodeId, - _attributes: &[ast::Attribute], + attributes: &[ast::Attribute], output_type: ty::FnOutput<'tcx>, abi: Abi, closure_env: closure::ClosureEnv<'b>) { @@ -1600,6 +1604,12 @@ pub fn trans_closure<'a, 'b, 'tcx>(ccx: &CrateContext<'a, 'tcx>, &arena); let mut bcx = init_function(&fcx, false, output_type); + if attributes.iter().any(|item| item.check_name("rustc_mir")) { + mir::trans_mir(bcx); + fcx.cleanup(); + return; + } + // cleanup scope for the incoming arguments let fn_cleanup_debug_loc = debuginfo::get_cleanup_debug_loc_for_ast_node(ccx, fn_ast_id, body.span, true); diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index b39b7818a6350..b5f192b972742 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -16,7 +16,7 @@ pub use self::ExprOrMethodCall::*; use session::Session; use llvm; -use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef}; +use llvm::{ValueRef, BasicBlockRef, BuilderRef, ContextRef, TypeKind}; use llvm::{True, False, Bool}; use middle::cfg; use middle::def; @@ -40,6 +40,7 @@ use middle::traits; use middle::ty::{self, HasTypeFlags, Ty}; use middle::ty::fold::{TypeFolder, TypeFoldable}; use rustc_front::hir; +use rustc_mir::repr::Mir; use util::nodemap::{FnvHashMap, NodeMap}; use arena::TypedArena; @@ -328,6 +329,11 @@ impl<'tcx> DropFlagHintsMap<'tcx> { // Function context. Every LLVM function we create will have one of // these. pub struct FunctionContext<'a, 'tcx: 'a> { + // The MIR for this function. At present, this is optional because + // we only have MIR available for things that are local to the + // crate. + pub mir: Option<&'a Mir<'tcx>>, + // The ValueRef returned from a call to llvm::LLVMAddFunction; the // address of the first instruction in the sequence of // instructions for this function that will go in the .text @@ -407,6 +413,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> { } impl<'a, 'tcx> FunctionContext<'a, 'tcx> { + pub fn mir(&self) -> &'a Mir<'tcx> { + self.mir.unwrap() + } + pub fn arg_offset(&self) -> usize { self.env_arg_pos() + if self.llenv.is_some() { 1 } else { 0 } } @@ -644,6 +654,10 @@ impl<'blk, 'tcx> BlockS<'blk, 'tcx> { } pub fn sess(&self) -> &'blk Session { self.fcx.ccx.sess() } + pub fn mir(&self) -> &'blk Mir<'tcx> { + self.fcx.mir() + } + pub fn name(&self, name: ast::Name) -> String { name.to_string() } @@ -1132,3 +1146,65 @@ pub fn inlined_variant_def<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, ccx.sess().bug(&format!("no variant for {:?}::{}", adt_def, inlined_vid)) }) } + +// To avoid UB from LLVM, these two functions mask RHS with an +// appropriate mask unconditionally (i.e. the fallback behavior for +// all shifts). For 32- and 64-bit types, this matches the semantics +// of Java. (See related discussion on #1877 and #10183.) + +pub fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + lhs: ValueRef, + rhs: ValueRef, + binop_debug_loc: DebugLoc) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); + build::Shl(bcx, lhs, rhs, binop_debug_loc) +} + +pub fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + lhs_t: Ty<'tcx>, + lhs: ValueRef, + rhs: ValueRef, + binop_debug_loc: DebugLoc) -> ValueRef { + let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs); + // #1877, #10183: Ensure that input is always valid + let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); + let is_signed = lhs_t.is_signed(); + if is_signed { + build::AShr(bcx, lhs, rhs, binop_debug_loc) + } else { + build::LShr(bcx, lhs, rhs, binop_debug_loc) + } +} + +fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + rhs: ValueRef, + debug_loc: DebugLoc) -> ValueRef { + let rhs_llty = val_ty(rhs); + build::And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc) +} + +pub fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, + llty: Type, + mask_llty: Type, + invert: bool) -> ValueRef { + let kind = llty.kind(); + match kind { + TypeKind::Integer => { + // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. + let val = llty.int_width() - 1; + if invert { + C_integral(mask_llty, !val, true) + } else { + C_integral(mask_llty, val, false) + } + }, + TypeKind::Vector => { + let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert); + build::VectorSplat(bcx, mask_llty.vector_length(), mask) + }, + _ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind), + } +} + diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs index 6144de7109fba..7648587e35268 100644 --- a/src/librustc_trans/trans/expr.rs +++ b/src/librustc_trans/trans/expr.rs @@ -2574,29 +2574,6 @@ impl OverflowOpViaInputCheck { } } -fn shift_mask_val<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - llty: Type, - mask_llty: Type, - invert: bool) -> ValueRef { - let kind = llty.kind(); - match kind { - TypeKind::Integer => { - // i8/u8 can shift by at most 7, i16/u16 by at most 15, etc. - let val = llty.int_width() - 1; - if invert { - C_integral(mask_llty, !val, true) - } else { - C_integral(mask_llty, val, false) - } - }, - TypeKind::Vector => { - let mask = shift_mask_val(bcx, llty.element_type(), mask_llty.element_type(), invert); - VectorSplat(bcx, mask_llty.vector_length(), mask) - }, - _ => panic!("shift_mask_val: expected Integer or Vector, found {:?}", kind), - } -} - // Check if an integer or vector contains a nonzero element. fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, value: ValueRef, @@ -2616,44 +2593,6 @@ fn build_nonzero_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } } -// To avoid UB from LLVM, these two functions mask RHS with an -// appropriate mask unconditionally (i.e. the fallback behavior for -// all shifts). For 32- and 64-bit types, this matches the semantics -// of Java. (See related discussion on #1877 and #10183.) - -fn build_unchecked_lshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lhs: ValueRef, - rhs: ValueRef, - binop_debug_loc: DebugLoc) -> ValueRef { - let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShl, lhs, rhs); - // #1877, #10183: Ensure that input is always valid - let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); - Shl(bcx, lhs, rhs, binop_debug_loc) -} - -fn build_unchecked_rshift<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - lhs_t: Ty<'tcx>, - lhs: ValueRef, - rhs: ValueRef, - binop_debug_loc: DebugLoc) -> ValueRef { - let rhs = base::cast_shift_expr_rhs(bcx, hir::BinOp_::BiShr, lhs, rhs); - // #1877, #10183: Ensure that input is always valid - let rhs = shift_mask_rhs(bcx, rhs, binop_debug_loc); - let is_signed = lhs_t.is_signed(); - if is_signed { - AShr(bcx, lhs, rhs, binop_debug_loc) - } else { - LShr(bcx, lhs, rhs, binop_debug_loc) - } -} - -fn shift_mask_rhs<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - rhs: ValueRef, - debug_loc: DebugLoc) -> ValueRef { - let rhs_llty = val_ty(rhs); - And(bcx, rhs, shift_mask_val(bcx, rhs_llty, rhs_llty, false), debug_loc) -} - fn with_overflow_check<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, oop: OverflowOp, info: NodeIdAndSpan, lhs_t: Ty<'tcx>, lhs: ValueRef, rhs: ValueRef, From 02017b30ebebfaeb64a5a86a885773f38057beba Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 21 Oct 2015 17:42:25 -0400 Subject: [PATCH 22/53] New trans codepath that builds fn body from MIR instead. --- src/librustc_trans/trans/common.rs | 6 + src/librustc_trans/trans/mir/block.rs | 106 ++++++++++ src/librustc_trans/trans/mir/constant.rs | 63 ++++++ src/librustc_trans/trans/mir/lvalue.rs | 149 ++++++++++++++ src/librustc_trans/trans/mir/mod.rs | 162 +++++++++++++++ src/librustc_trans/trans/mir/operand.rs | 90 ++++++++ src/librustc_trans/trans/mir/rvalue.rs | 238 ++++++++++++++++++++++ src/librustc_trans/trans/mir/statement.rs | 48 +++++ src/librustc_trans/trans/mod.rs | 1 + src/test/run-pass/mir_trans_spike1.rs | 24 +++ 10 files changed, 887 insertions(+) create mode 100644 src/librustc_trans/trans/mir/block.rs create mode 100644 src/librustc_trans/trans/mir/constant.rs create mode 100644 src/librustc_trans/trans/mir/lvalue.rs create mode 100644 src/librustc_trans/trans/mir/mod.rs create mode 100644 src/librustc_trans/trans/mir/operand.rs create mode 100644 src/librustc_trans/trans/mir/rvalue.rs create mode 100644 src/librustc_trans/trans/mir/statement.rs create mode 100644 src/test/run-pass/mir_trans_spike1.rs diff --git a/src/librustc_trans/trans/common.rs b/src/librustc_trans/trans/common.rs index b5f192b972742..8d6ba53dd222d 100644 --- a/src/librustc_trans/trans/common.rs +++ b/src/librustc_trans/trans/common.rs @@ -743,6 +743,12 @@ pub fn C_floating(s: &str, t: Type) -> ValueRef { } } +pub fn C_floating_f64(f: f64, t: Type) -> ValueRef { + unsafe { + llvm::LLVMConstReal(t.to_ref(), f) + } +} + pub fn C_nil(ccx: &CrateContext) -> ValueRef { C_struct(ccx, &[], false) } diff --git a/src/librustc_trans/trans/mir/block.rs b/src/librustc_trans/trans/mir/block.rs new file mode 100644 index 0000000000000..c9f4123c17127 --- /dev/null +++ b/src/librustc_trans/trans/mir/block.rs @@ -0,0 +1,106 @@ +// Copyright 2012-2014 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 llvm::BasicBlockRef; +use rustc_mir::repr as mir; +use trans::base; +use trans::build; +use trans::common::Block; +use trans::debuginfo::DebugLoc; + +use super::MirContext; + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_block(&mut self, bb: mir::BasicBlock) { + debug!("trans_block({:?})", bb); + + let mut bcx = self.bcx(bb); + let data = self.mir.basic_block_data(bb); + + for statement in &data.statements { + bcx = self.trans_statement(bcx, statement); + } + + debug!("trans_block: terminator: {:?}", data.terminator); + + match data.terminator { + mir::Terminator::Goto { target } => { + build::Br(bcx, self.llblock(target), DebugLoc::None) + } + + mir::Terminator::Panic { .. } => { + unimplemented!() + } + + mir::Terminator::If { ref cond, targets: [true_bb, false_bb] } => { + let cond = self.trans_operand(bcx, cond); + let lltrue = self.llblock(true_bb); + let llfalse = self.llblock(false_bb); + build::CondBr(bcx, cond.llval, lltrue, llfalse, DebugLoc::None); + } + + mir::Terminator::Switch { .. } => { + unimplemented!() + } + + mir::Terminator::Diverge => { + if let Some(llpersonalityslot) = self.llpersonalityslot { + let lp = build::Load(bcx, llpersonalityslot); + // FIXME(lifetime) base::call_lifetime_end(bcx, self.personality); + build::Resume(bcx, lp); + } else { + // This fn never encountered anything fallible, so + // a Diverge cannot actually happen. Note that we + // do a total hack to ensure that we visit the + // DIVERGE block last. + build::Unreachable(bcx); + } + } + + mir::Terminator::Return => { + let return_ty = bcx.monomorphize(&self.mir.return_ty); + base::build_return_block(bcx.fcx, bcx, return_ty, DebugLoc::None); + } + + mir::Terminator::Call { .. } => { + unimplemented!() + //let llbb = unimplemented!(); // self.make_landing_pad(panic_bb); + // + //let tr_dest = self.trans_lvalue(bcx, &data.destination); + // + //// Create the callee. This will always be a fn + //// ptr and hence a kind of scalar. + //let callee = self.trans_operand(bcx, &data.func); + // + //// Process the arguments. + // + //let args = unimplemented!(); + // + //callee::trans_call_inner(bcx, + // DebugLoc::None, + // |bcx, _| Callee { + // bcx: bcx, + // data: CalleeData::Fn(callee.llval), + // ty: callee.ty, + // }, + // args, + // Some(Dest::SaveIn(tr_dest.llval))); + } + } + } + + fn bcx(&self, bb: mir::BasicBlock) -> Block<'bcx, 'tcx> { + self.blocks[bb.index()] + } + + fn llblock(&self, bb: mir::BasicBlock) -> BasicBlockRef { + self.blocks[bb.index()].llbb + } +} diff --git a/src/librustc_trans/trans/mir/constant.rs b/src/librustc_trans/trans/mir/constant.rs new file mode 100644 index 0000000000000..1b61001834a99 --- /dev/null +++ b/src/librustc_trans/trans/mir/constant.rs @@ -0,0 +1,63 @@ +// Copyright 2012-2014 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 llvm::ValueRef; +use rustc::middle::const_eval::ConstVal; +use rustc_mir::repr as mir; +use trans::consts::{self, TrueConst}; +use trans::common::{self, Block}; +use trans::type_of; + +use super::MirContext; + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_constant(&mut self, + bcx: Block<'bcx, 'tcx>, + constant: &mir::Constant<'tcx>) + -> ValueRef + { + let ccx = bcx.ccx(); + let constant_ty = bcx.monomorphize(&constant.ty); + let llty = type_of::type_of(ccx, constant_ty); + match constant.literal { + mir::Literal::Item { .. } => { + unimplemented!() + } + mir::Literal::Value { ref value } => { + match *value { + ConstVal::Float(v) => common::C_floating_f64(v, llty), + ConstVal::Bool(v) => common::C_bool(ccx, v), + ConstVal::Int(v) => common::C_integral(llty, v as u64, true), + ConstVal::Uint(v) => common::C_integral(llty, v, false), + ConstVal::Str(ref v) => common::C_str_slice(ccx, v.clone()), + ConstVal::ByteStr(ref v) => consts::addr_of(ccx, + common::C_bytes(ccx, v), + 1, + "byte_str"), + ConstVal::Struct(id) | ConstVal::Tuple(id) => { + let expr = bcx.tcx().map.expect_expr(id); + let (llval, _) = match consts::const_expr(ccx, + expr, + bcx.fcx.param_substs, + None, + TrueConst::Yes) { + Ok(v) => v, + Err(_) => panic!("constant eval failure"), + }; + llval + } + ConstVal::Function(_) => { + unimplemented!() + } + } + } + } + } +} diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs new file mode 100644 index 0000000000000..282c6a7e6de17 --- /dev/null +++ b/src/librustc_trans/trans/mir/lvalue.rs @@ -0,0 +1,149 @@ +// Copyright 2012-2014 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 llvm::ValueRef; +use rustc::middle::ty::Ty; +use rustc_mir::repr as mir; +use rustc_mir::tcx::LvalueTy; +use trans::adt; +use trans::base; +use trans::build; +use trans::common::{self, Block}; +use trans::debuginfo::DebugLoc; +use trans::machine; +use trans::tvec; + +use super::MirContext; + +#[derive(Copy, Clone)] +pub struct LvalueRef<'tcx> { + /// Pointer to the contents of the lvalue + pub llval: ValueRef, + + /// Monomorphized type of this lvalue, including variant information + pub ty: LvalueTy<'tcx>, +} + +impl<'tcx> LvalueRef<'tcx> { + pub fn new(llval: ValueRef, lvalue_ty: LvalueTy<'tcx>) -> LvalueRef<'tcx> { + LvalueRef { llval: llval, ty: lvalue_ty } + } + + pub fn alloca<'bcx>(bcx: Block<'bcx, 'tcx>, + ty: Ty<'tcx>, + name: &str) + -> LvalueRef<'tcx> + { + let lltemp = base::alloc_ty(bcx, ty, name); + LvalueRef::new(lltemp, LvalueTy::from_ty(ty)) + } +} + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_lvalue(&mut self, + bcx: Block<'bcx, 'tcx>, + lvalue: &mir::Lvalue<'tcx>) + -> LvalueRef<'tcx> { + debug!("trans_lvalue(lvalue={:?})", lvalue); + + let fcx = bcx.fcx; + let ccx = fcx.ccx; + let tcx = bcx.tcx(); + match *lvalue { + mir::Lvalue::Var(index) => self.vars[index as usize], + mir::Lvalue::Temp(index) => self.temps[index as usize], + mir::Lvalue::Arg(index) => self.args[index as usize], + mir::Lvalue::Static(_def_id) => unimplemented!(), + mir::Lvalue::ReturnPointer => { + let return_ty = bcx.monomorphize(&self.mir.return_ty); + let llval = fcx.get_ret_slot(bcx, return_ty, "return"); + LvalueRef::new(llval, LvalueTy::from_ty(return_ty.unwrap())) + } + mir::Lvalue::Projection(ref projection) => { + let tr_base = self.trans_lvalue(bcx, &projection.base); + let projected_ty = tr_base.ty.projection_ty(tcx, &projection.elem); + let llprojected = match projection.elem { + mir::ProjectionElem::Deref => { + let base_ty = tr_base.ty.to_ty(tcx); + base::load_ty(bcx, tr_base.llval, base_ty) + } + mir::ProjectionElem::Field(ref field) => { + let base_ty = tr_base.ty.to_ty(tcx); + let base_repr = adt::represent_type(ccx, base_ty); + let discr = match tr_base.ty { + LvalueTy::Ty { .. } => 0, + LvalueTy::Downcast { adt_def: _, substs: _, variant_index: v } => v, + }; + let discr = discr as u64; + adt::trans_field_ptr(bcx, &base_repr, tr_base.llval, discr, field.index()) + } + mir::ProjectionElem::Index(ref index) => { + let base_ty = tr_base.ty.to_ty(tcx); + let index = self.trans_operand(bcx, index); + let llindex = self.prepare_index(bcx, index.llval); + let (llbase, _) = tvec::get_base_and_len(bcx, tr_base.llval, base_ty); + build::InBoundsGEP(bcx, llbase, &[llindex]) + } + mir::ProjectionElem::ConstantIndex { offset, + from_end: false, + min_length: _ } => { + let base_ty = tr_base.ty.to_ty(tcx); + let lloffset = common::C_u32(bcx.ccx(), offset); + let llindex = self.prepare_index(bcx, lloffset); + let (llbase, _) = tvec::get_base_and_len(bcx, + tr_base.llval, + base_ty); + build::InBoundsGEP(bcx, llbase, &[llindex]) + } + mir::ProjectionElem::ConstantIndex { offset, + from_end: true, + min_length: _ } => { + let lloffset = common::C_u32(bcx.ccx(), offset); + let base_ty = tr_base.ty.to_ty(tcx); + let (llbase, lllen) = tvec::get_base_and_len(bcx, + tr_base.llval, + base_ty); + let llindex = build::Sub(bcx, lllen, lloffset, DebugLoc::None); + let llindex = self.prepare_index(bcx, llindex); + build::InBoundsGEP(bcx, llbase, &[llindex]) + } + mir::ProjectionElem::Downcast(..) => { + tr_base.llval + } + }; + LvalueRef { + llval: llprojected, + ty: projected_ty, + } + } + } + } + + /// Adjust the bitwidth of an index since LLVM is less forgiving + /// than we are. + /// + /// nmatsakis: is this still necessary? Not sure. + fn prepare_index(&mut self, + bcx: Block<'bcx, 'tcx>, + llindex: ValueRef) + -> ValueRef + { + let ccx = bcx.ccx(); + let index_size = machine::llbitsize_of_real(bcx.ccx(), common::val_ty(llindex)); + let int_size = machine::llbitsize_of_real(bcx.ccx(), ccx.int_type()); + if index_size < int_size { + build::ZExt(bcx, llindex, ccx.int_type()) + } else if index_size > int_size { + build::Trunc(bcx, llindex, ccx.int_type()) + } else { + llindex + } + } +} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs new file mode 100644 index 0000000000000..6ed839d1a442d --- /dev/null +++ b/src/librustc_trans/trans/mir/mod.rs @@ -0,0 +1,162 @@ +// Copyright 2012-2014 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 libc::c_uint; +use llvm::{self, ValueRef}; +use rustc_mir::repr as mir; +use rustc_mir::tcx::LvalueTy; +use std::cell::Cell; +use trans::base; +use trans::build; +use trans::common::{self, Block}; +use trans::debuginfo::DebugLoc; +use trans::expr; +use trans::type_of; + +use self::lvalue::LvalueRef; + +// FIXME DebugLoc is always None right now + +/// Master context for translating MIR. +pub struct MirContext<'bcx, 'tcx:'bcx> { + mir: &'bcx mir::Mir<'tcx>, + + /// When unwinding is initiated, we have to store this personality + /// value somewhere so that we can load it and re-use it in the + /// resume instruction. The personality is (afaik) some kind of + /// value used for C++ unwinding, which must filter by type: we + /// don't really care about it very much. Anyway, this value + /// contains an alloca into which the personality is stored and + /// then later loaded when generating the DIVERGE_BLOCK. + llpersonalityslot: Option, + + /// A `Block` for each MIR `BasicBlock` + blocks: Vec>, + + /// An LLVM alloca for each MIR `VarDecl` + vars: Vec>, + + /// An LLVM alloca for each MIR `TempDecl` + temps: Vec>, + + /// The arguments to the function; as args are lvalues, these are + /// always indirect, though we try to avoid creating an alloca + /// when we can (and just reuse the pointer the caller provided). + args: Vec>, +} + +/////////////////////////////////////////////////////////////////////////// + +pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { + let fcx = bcx.fcx; + let mir = bcx.mir(); + + let mir_blocks = bcx.mir().all_basic_blocks(); + + // Allocate variable and temp allocas + let vars = mir.var_decls.iter() + .map(|decl| (bcx.monomorphize(&decl.ty), decl.name)) + .map(|(mty, name)| LvalueRef::alloca(bcx, mty, &name.as_str())) + .collect(); + let temps = mir.temp_decls.iter() + .map(|decl| bcx.monomorphize(&decl.ty)) + .enumerate() + .map(|(i, mty)| LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i))) + .collect(); + let args = arg_value_refs(bcx, mir); + + // Allocate a `Block` for every basic block + let block_bcxs: Vec> = + mir_blocks.iter() + .map(|&bb| fcx.new_block(false, &format!("{:?}", bb), None)) + .collect(); + + // Branch to the START block + let start_bcx = block_bcxs[mir::START_BLOCK.index()]; + build::Br(bcx, start_bcx.llbb, DebugLoc::None); + + let mut mircx = MirContext { + mir: mir, + llpersonalityslot: None, + blocks: block_bcxs, + vars: vars, + temps: temps, + args: args, + }; + + // Translate the body of each block + for &bb in &mir_blocks { + if bb != mir::DIVERGE_BLOCK { + mircx.trans_block(bb); + } + } + + // Total hack: translate DIVERGE_BLOCK last. This is so that any + // panics which the fn may do can initialize the + // `llpersonalityslot` cell. We don't do this up front because the + // LLVM type of it is (frankly) annoying to compute. + mircx.trans_block(mir::DIVERGE_BLOCK); +} + +/// Produce, for each argument, a `ValueRef` pointing at the +/// argument's value. As arguments are lvalues, these are always +/// indirect. +fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>, + mir: &mir::Mir<'tcx>) + -> Vec> { + // FIXME tupled_args? I think I'd rather that mapping is done in MIR land though + let fcx = bcx.fcx; + let tcx = bcx.tcx(); + let mut idx = fcx.arg_offset() as c_uint; + mir.arg_decls + .iter() + .enumerate() + .map(|(arg_index, arg_decl)| { + let arg_ty = bcx.monomorphize(&arg_decl.ty); + let llval = if type_of::arg_is_indirect(bcx.ccx(), arg_ty) { + // Don't copy an indirect argument to an alloca, the caller + // already put it in a temporary alloca and gave it up, unless + // we emit extra-debug-info, which requires local allocas :(. + // FIXME: lifetimes, debug info + let llarg = llvm::get_param(fcx.llfn, idx); + idx += 1; + llarg + } else if common::type_is_fat_ptr(tcx, arg_ty) { + // we pass fat pointers as two words, but we want to + // represent them internally as a pointer two two words, + // so make an alloca to store them in. + let lldata = llvm::get_param(fcx.llfn, idx); + let llextra = llvm::get_param(fcx.llfn, idx + 1); + idx += 2; + let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); + build::Store(bcx, lldata, expr::get_dataptr(bcx, lltemp)); + build::Store(bcx, llextra, expr::get_dataptr(bcx, lltemp)); + lltemp + } else { + // otherwise, arg is passed by value, so make a + // temporary and store it there + let llarg = llvm::get_param(fcx.llfn, idx); + idx += 1; + let lltemp = base::alloc_ty(bcx, arg_ty, &format!("arg{}", arg_index)); + build::Store(bcx, llarg, lltemp); + lltemp + }; + LvalueRef::new(llval, LvalueTy::from_ty(arg_ty)) + }) + .collect() +} + +mod block; +mod constant; +mod lvalue; +mod rvalue; +mod operand; +mod statement; + diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs new file mode 100644 index 0000000000000..786b84ae80759 --- /dev/null +++ b/src/librustc_trans/trans/mir/operand.rs @@ -0,0 +1,90 @@ +// Copyright 2012-2014 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 llvm::ValueRef; +use rustc::middle::ty::Ty; +use rustc_mir::repr as mir; +use trans::base; +use trans::build; +use trans::common::Block; +use trans::datum; + +use super::MirContext; + +pub struct OperandRef<'tcx> { + // This will be "indirect" if `appropriate_rvalue_mode` returns + // ByRef, and otherwise ByValue. + pub llval: ValueRef, + + // The type of value being returned. + pub ty: Ty<'tcx> +} + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_operand(&mut self, + bcx: Block<'bcx, 'tcx>, + operand: &mir::Operand<'tcx>) + -> OperandRef<'tcx> + { + debug!("trans_operand(operand={:?})", operand); + + match *operand { + mir::Operand::Consume(ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let ty = tr_lvalue.ty.to_ty(bcx.tcx()); + debug!("trans_operand: tr_lvalue={} @ {:?}", + bcx.val_to_string(tr_lvalue.llval), + ty); + let llval = match datum::appropriate_rvalue_mode(bcx.ccx(), ty) { + datum::ByValue => build::Load(bcx, tr_lvalue.llval), + datum::ByRef => tr_lvalue.llval, + }; + OperandRef { + llval: llval, + ty: ty + } + } + + mir::Operand::Constant(ref constant) => { + let llval = self.trans_constant(bcx, constant); + let ty = bcx.monomorphize(&constant.ty); + OperandRef { + llval: llval, + ty: ty, + } + } + } + } + + pub fn trans_operand_into(&mut self, + bcx: Block<'bcx, 'tcx>, + lldest: ValueRef, + operand: &mir::Operand<'tcx>) + { + debug!("trans_operand_into(lldest={}, operand={:?})", + bcx.val_to_string(lldest), + operand); + + match *operand { + mir::Operand::Consume(ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let lvalue_ty = tr_lvalue.ty.to_ty(bcx.tcx()); + debug!("trans_operand_into: tr_lvalue={} @ {:?}", + bcx.val_to_string(tr_lvalue.llval), + lvalue_ty); + base::memcpy_ty(bcx, lldest, tr_lvalue.llval, lvalue_ty); + } + + mir::Operand::Constant(..) => { + unimplemented!() + } + } + } +} diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs new file mode 100644 index 0000000000000..416aa061276fe --- /dev/null +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -0,0 +1,238 @@ +// Copyright 2012-2014 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 back::abi; +use llvm::ValueRef; +use rustc::middle::ty::Ty; +use rustc_front::hir; +use rustc_mir::repr as mir; + +use trans::asm; +use trans::base; +use trans::build; +use trans::common::{self, Block, Result}; +use trans::debuginfo::DebugLoc; +use trans::declare; +use trans::machine; +use trans::type_::Type; +use trans::type_of; +use trans::tvec; + +use super::MirContext; +use super::operand::OperandRef; + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_rvalue(&mut self, + bcx: Block<'bcx, 'tcx>, + lldest: ValueRef, + rvalue: &mir::Rvalue<'tcx>) + -> Block<'bcx, 'tcx> + { + debug!("trans_rvalue(lldest={}, rvalue={:?})", + bcx.val_to_string(lldest), + rvalue); + + match *rvalue { + mir::Rvalue::Use(ref operand) => { + self.trans_operand_into(bcx, lldest, operand); + bcx + } + + mir::Rvalue::Cast(..) => { + unimplemented!() + } + + mir::Rvalue::Repeat(..) => { + unimplemented!() + } + + mir::Rvalue::Ref(_, _, ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + // Note: lvalues are indirect, so storing the `llval` into the + // destination effectively creates a reference. + build::Store(bcx, tr_lvalue.llval, lldest); + bcx + } + + mir::Rvalue::Len(ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let (_, lllen) = tvec::get_base_and_len(bcx, + tr_lvalue.llval, + tr_lvalue.ty.to_ty(bcx.tcx())); + build::Store(bcx, lllen, lldest); + bcx + } + + mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { + let lhs = self.trans_operand(bcx, lhs); + let rhs = self.trans_operand(bcx, rhs); + let is_float = lhs.ty.is_fp(); + let is_signed = lhs.ty.is_signed(); + let binop_debug_loc = DebugLoc::None; + let llval = match op { + mir::BinOp::Add => if is_float { + build::FAdd(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else { + build::Add(bcx, lhs.llval, rhs.llval, binop_debug_loc) + }, + mir::BinOp::Sub => if is_float { + build::FSub(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else { + build::Sub(bcx, lhs.llval, rhs.llval, binop_debug_loc) + }, + mir::BinOp::Mul => if is_float { + build::FMul(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else { + build::Mul(bcx, lhs.llval, rhs.llval, binop_debug_loc) + }, + mir::BinOp::Div => if is_float { + build::FDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else if is_signed { + build::SDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else { + build::UDiv(bcx, lhs.llval, rhs.llval, binop_debug_loc) + }, + mir::BinOp::Rem => if is_float { + // LLVM currently always lowers the `frem` instructions appropriate + // library calls typically found in libm. Notably f64 gets wired up + // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for + // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's + // instead just an inline function in a header that goes up to a + // f64, uses `fmod`, and then comes back down to a f32. + // + // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will + // still unconditionally lower frem instructions over 32-bit floats + // to a call to `fmodf`. To work around this we special case MSVC + // 32-bit float rem instructions and instead do the call out to + // `fmod` ourselves. + // + // Note that this is currently duplicated with src/libcore/ops.rs + // which does the same thing, and it would be nice to perhaps unify + // these two implementations on day! Also note that we call `fmod` + // for both 32 and 64-bit floats because if we emit any FRem + // instruction at all then LLVM is capable of optimizing it into a + // 32-bit FRem (which we're trying to avoid). + let tcx = bcx.tcx(); + let use_fmod = tcx.sess.target.target.options.is_like_msvc && + tcx.sess.target.target.arch == "x86"; + if use_fmod { + let f64t = Type::f64(bcx.ccx()); + let fty = Type::func(&[f64t, f64t], &f64t); + let llfn = declare::declare_cfn(bcx.ccx(), "fmod", fty, + tcx.types.f64); + if lhs.ty == tcx.types.f32 { + let lllhs = build::FPExt(bcx, lhs.llval, f64t); + let llrhs = build::FPExt(bcx, rhs.llval, f64t); + let llres = build::Call(bcx, llfn, &[lllhs, llrhs], + None, binop_debug_loc); + build::FPTrunc(bcx, llres, Type::f32(bcx.ccx())) + } else { + build::Call(bcx, llfn, &[lhs.llval, rhs.llval], + None, binop_debug_loc) + } + } else { + build::FRem(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } + } else if is_signed { + build::SRem(bcx, lhs.llval, rhs.llval, binop_debug_loc) + } else { + build::URem(bcx, lhs.llval, rhs.llval, binop_debug_loc) + }, + mir::BinOp::BitOr => build::Or(bcx, lhs.llval, rhs.llval, binop_debug_loc), + mir::BinOp::BitAnd => build::And(bcx, lhs.llval, rhs.llval, binop_debug_loc), + mir::BinOp::BitXor => build::Xor(bcx, lhs.llval, rhs.llval, binop_debug_loc), + mir::BinOp::Shl => common::build_unchecked_lshift(bcx, + lhs.llval, + rhs.llval, + binop_debug_loc), + mir::BinOp::Shr => common::build_unchecked_rshift(bcx, + lhs.ty, + lhs.llval, + rhs.llval, + binop_debug_loc), + mir::BinOp::Eq => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiEq, binop_debug_loc), + mir::BinOp::Lt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiLt, binop_debug_loc), + mir::BinOp::Le => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiLe, binop_debug_loc), + mir::BinOp::Ne => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiNe, binop_debug_loc), + mir::BinOp::Ge => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiGe, binop_debug_loc), + mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, + hir::BiGt, binop_debug_loc), + }; + build::Store(bcx, llval, lldest); + bcx + } + + mir::Rvalue::UnaryOp(op, ref operand) => { + let operand = self.trans_operand(bcx, operand); + let is_float = operand.ty.is_fp(); + let debug_loc = DebugLoc::None; + let llval = match op { + mir::UnOp::Not => build::Not(bcx, operand.llval, debug_loc), + mir::UnOp::Neg => if is_float { + build::FNeg(bcx, operand.llval, debug_loc) + } else { + build::Neg(bcx, operand.llval, debug_loc) + } + }; + build::Store(bcx, llval, lldest); + bcx + } + + mir::Rvalue::Box(content_ty) => { + let content_ty: Ty<'tcx> = content_ty; + let llty = type_of::type_of(bcx.ccx(), content_ty); + let llsize = machine::llsize_of(bcx.ccx(), llty); + let align = type_of::align_of(bcx.ccx(), content_ty); + let llalign = common::C_uint(bcx.ccx(), align); + let llty_ptr = llty.ptr_to(); + let box_ty = bcx.tcx().mk_box(content_ty); + let Result { bcx, val: llval } = base::malloc_raw_dyn(bcx, + llty_ptr, + box_ty, + llsize, + llalign, + DebugLoc::None); + build::Store(bcx, llval, lldest); + bcx + } + + mir::Rvalue::Aggregate(_, ref operands) => { + for (i, operand) in operands.iter().enumerate() { + let lldest_i = build::GEPi(bcx, lldest, &[0, i]); + self.trans_operand_into(bcx, lldest_i, operand); + } + bcx + } + + mir::Rvalue::Slice { ref input, from_start, from_end } => { + let ccx = bcx.ccx(); + let input = self.trans_lvalue(bcx, input); + let (llbase, lllen) = tvec::get_base_and_len(bcx, + input.llval, + input.ty.to_ty(bcx.tcx())); + let llbase1 = build::GEPi(bcx, llbase, &[from_start]); + let adj = common::C_uint(ccx, from_start + from_end); + let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); + build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR])); + build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA])); + bcx + } + + mir::Rvalue::InlineAsm(inline_asm) => { + asm::trans_inline_asm(bcx, inline_asm) + } + } + } +} diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs new file mode 100644 index 0000000000000..17a20fb817c89 --- /dev/null +++ b/src/librustc_trans/trans/mir/statement.rs @@ -0,0 +1,48 @@ +// Copyright 2012-2014 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 rustc::middle::ty::LvaluePreference; +use rustc_mir::repr as mir; +use trans::common::Block; +use trans::debuginfo::DebugLoc; +use trans::glue; + +use super::MirContext; + +impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { + pub fn trans_statement(&mut self, + bcx: Block<'bcx, 'tcx>, + statement: &mir::Statement<'tcx>) + -> Block<'bcx, 'tcx> { + debug!("trans_statement(statement={:?})", statement); + + match statement.kind { + mir::StatementKind::Assign(ref lvalue, ref rvalue) => { + let tr_dest = self.trans_lvalue(bcx, lvalue); + self.trans_rvalue(bcx, tr_dest.llval, rvalue); + bcx + } + + mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let ty = tr_lvalue.ty.to_ty(bcx.tcx()); + glue::drop_ty(bcx, tr_lvalue.llval, ty, DebugLoc::None) + } + + mir::StatementKind::Drop(mir::DropKind::Free, ref lvalue) => { + let tr_lvalue = self.trans_lvalue(bcx, lvalue); + let ty = tr_lvalue.ty.to_ty(bcx.tcx()); + let content_ty = ty.builtin_deref(true, LvaluePreference::NoPreference); + let content_ty = content_ty.unwrap().ty; + glue::trans_exchange_free_ty(bcx, tr_lvalue.llval, content_ty, DebugLoc::None) + } + } + } +} diff --git a/src/librustc_trans/trans/mod.rs b/src/librustc_trans/trans/mod.rs index 04854501312bf..fa37b00553982 100644 --- a/src/librustc_trans/trans/mod.rs +++ b/src/librustc_trans/trans/mod.rs @@ -52,6 +52,7 @@ mod llrepr; mod machine; mod _match; mod meth; +mod mir; mod monomorphize; mod tvec; mod type_; diff --git a/src/test/run-pass/mir_trans_spike1.rs b/src/test/run-pass/mir_trans_spike1.rs new file mode 100644 index 0000000000000..9a06ab78e73b4 --- /dev/null +++ b/src/test/run-pass/mir_trans_spike1.rs @@ -0,0 +1,24 @@ +// Copyright 2012 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// A simple spike test for MIR version of trans. + +#![feature(rustc_attrs)] + +#[rustc_mir] +fn sum(x: i32, y: i32) -> i32 { + x + y +} + +fn main() { + let x = sum(22, 44); + assert_eq!(x, 66); + println!("sum()={:?}", x); +} From e84829d51d9aa8e2623dabd4dcd4935d22008cb5 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 2 Nov 2015 09:39:59 -0500 Subject: [PATCH 23/53] Plumbing to omit allocas for temps when possible (currently unused) --- src/librustc_trans/lib.rs | 1 + src/librustc_trans/trans/mir/lvalue.rs | 9 +- src/librustc_trans/trans/mir/mod.rs | 38 +++++- src/librustc_trans/trans/mir/rvalue.rs | 134 ++++++++++++++++------ src/librustc_trans/trans/mir/statement.rs | 28 ++++- 5 files changed, 166 insertions(+), 44 deletions(-) diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs index bc5b6f6b9d7d9..84ce458ed14f7 100644 --- a/src/librustc_trans/lib.rs +++ b/src/librustc_trans/lib.rs @@ -51,6 +51,7 @@ extern crate graphviz; extern crate libc; extern crate rustc; extern crate rustc_back; +extern crate rustc_data_structures; extern crate rustc_front; extern crate rustc_llvm as llvm; extern crate rustc_mir; diff --git a/src/librustc_trans/trans/mir/lvalue.rs b/src/librustc_trans/trans/mir/lvalue.rs index 282c6a7e6de17..1ce7b55a9c686 100644 --- a/src/librustc_trans/trans/mir/lvalue.rs +++ b/src/librustc_trans/trans/mir/lvalue.rs @@ -20,7 +20,7 @@ use trans::debuginfo::DebugLoc; use trans::machine; use trans::tvec; -use super::MirContext; +use super::{MirContext, TempRef}; #[derive(Copy, Clone)] pub struct LvalueRef<'tcx> { @@ -58,7 +58,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let tcx = bcx.tcx(); match *lvalue { mir::Lvalue::Var(index) => self.vars[index as usize], - mir::Lvalue::Temp(index) => self.temps[index as usize], + mir::Lvalue::Temp(index) => match self.temps[index as usize] { + TempRef::Lvalue(lvalue) => + lvalue, + TempRef::Operand(..) => + tcx.sess.bug(&format!("using operand temp {:?} as lvalue", lvalue)), + }, mir::Lvalue::Arg(index) => self.args[index as usize], mir::Lvalue::Static(_def_id) => unimplemented!(), mir::Lvalue::ReturnPointer => { diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 6ed839d1a442d..760018b4313c8 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -10,9 +10,9 @@ use libc::c_uint; use llvm::{self, ValueRef}; +use rustc_data_structures::fnv::FnvHashSet; use rustc_mir::repr as mir; use rustc_mir::tcx::LvalueTy; -use std::cell::Cell; use trans::base; use trans::build; use trans::common::{self, Block}; @@ -21,6 +21,7 @@ use trans::expr; use trans::type_of; use self::lvalue::LvalueRef; +use self::operand::OperandRef; // FIXME DebugLoc is always None right now @@ -43,8 +44,19 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { /// An LLVM alloca for each MIR `VarDecl` vars: Vec>, - /// An LLVM alloca for each MIR `TempDecl` - temps: Vec>, + /// The location where each MIR `TempDecl` is stored. This is + /// usually an `LvalueRef` representing an alloca, but not always: + /// sometimes we can skip the alloca and just store the value + /// directly using an `OperandRef`, which makes for tighter LLVM + /// IR. The conditions for using an `OperandRef` are as follows: + /// + /// - the type of the temporary must be judged "immediate" by `type_is_immediate` + /// - the operand must never be referenced indirectly + /// - we should not take its address using the `&` operator + /// - nor should it appear in an lvalue path like `tmp.a` + /// - the operand must be defined by an rvalue that can generate immediate + /// values + temps: Vec>, /// The arguments to the function; as args are lvalues, these are /// always indirect, though we try to avoid creating an alloca @@ -52,6 +64,11 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { args: Vec>, } +enum TempRef<'tcx> { + Lvalue(LvalueRef<'tcx>), + Operand(Option>), +} + /////////////////////////////////////////////////////////////////////////// pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { @@ -60,6 +77,10 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { let mir_blocks = bcx.mir().all_basic_blocks(); + // Analyze the temps to determine which must be lvalues + // FIXME + let lvalue_temps: FnvHashSet = (0..mir.temp_decls.len()).collect(); + // Allocate variable and temp allocas let vars = mir.var_decls.iter() .map(|decl| (bcx.monomorphize(&decl.ty), decl.name)) @@ -68,7 +89,16 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { let temps = mir.temp_decls.iter() .map(|decl| bcx.monomorphize(&decl.ty)) .enumerate() - .map(|(i, mty)| LvalueRef::alloca(bcx, mty, &format!("temp{:?}", i))) + .map(|(i, mty)| if lvalue_temps.contains(&i) { + TempRef::Lvalue(LvalueRef::alloca(bcx, + mty, + &format!("temp{:?}", i))) + } else { + // If this is an immediate temp, we do not create an + // alloca in advance. Instead we wait until we see the + // definition and update the operand there. + TempRef::Operand(None) + }) .collect(); let args = arg_value_refs(bcx, mir); diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 416aa061276fe..c82726fd0e577 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -53,12 +53,87 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { unimplemented!() } + mir::Rvalue::Aggregate(_, ref operands) => { + for (i, operand) in operands.iter().enumerate() { + let lldest_i = build::GEPi(bcx, lldest, &[0, i]); + self.trans_operand_into(bcx, lldest_i, operand); + } + bcx + } + + mir::Rvalue::Slice { ref input, from_start, from_end } => { + let ccx = bcx.ccx(); + let input = self.trans_lvalue(bcx, input); + let (llbase, lllen) = tvec::get_base_and_len(bcx, + input.llval, + input.ty.to_ty(bcx.tcx())); + let llbase1 = build::GEPi(bcx, llbase, &[from_start]); + let adj = common::C_uint(ccx, from_start + from_end); + let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); + build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR])); + build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA])); + bcx + } + + mir::Rvalue::InlineAsm(inline_asm) => { + asm::trans_inline_asm(bcx, inline_asm) + } + + _ => { + assert!(self.rvalue_creates_operand(rvalue)); + let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); + build::Store(bcx, temp.llval, lldest); + bcx + } + } + } + + pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Use(..) | // (*) + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Box(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) | + mir::Rvalue::Slice { .. } | + mir::Rvalue::InlineAsm(..) => + false, + } + + // (*) this is only true if the type is suitable + } + + pub fn trans_rvalue_operand(&mut self, + bcx: Block<'bcx, 'tcx>, + rvalue: &mir::Rvalue<'tcx>) + -> (Block<'bcx, 'tcx>, OperandRef<'tcx>) + { + assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + + match *rvalue { + mir::Rvalue::Use(ref operand) => { + let operand = self.trans_operand(bcx, operand); + (bcx, operand) + } + + mir::Rvalue::Cast(..) => { + unimplemented!() + } + mir::Rvalue::Ref(_, _, ref lvalue) => { let tr_lvalue = self.trans_lvalue(bcx, lvalue); + // Note: lvalues are indirect, so storing the `llval` into the // destination effectively creates a reference. - build::Store(bcx, tr_lvalue.llval, lldest); - bcx + (bcx, OperandRef { + llval: tr_lvalue.llval, + ty: tr_lvalue.ty.to_ty(bcx.tcx()), + }) } mir::Rvalue::Len(ref lvalue) => { @@ -66,8 +141,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let (_, lllen) = tvec::get_base_and_len(bcx, tr_lvalue.llval, tr_lvalue.ty.to_ty(bcx.tcx())); - build::Store(bcx, lllen, lldest); - bcx + (bcx, OperandRef { + llval: lllen, + ty: bcx.tcx().types.usize, + }) } mir::Rvalue::BinaryOp(op, ref lhs, ref rhs) => { @@ -170,8 +247,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::BinOp::Gt => base::compare_scalar_types(bcx, lhs.llval, rhs.llval, lhs.ty, hir::BiGt, binop_debug_loc), }; - build::Store(bcx, llval, lldest); - bcx + (bcx, OperandRef { + llval: llval, + ty: lhs.ty, + }) } mir::Rvalue::UnaryOp(op, ref operand) => { @@ -186,12 +265,14 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { build::Neg(bcx, operand.llval, debug_loc) } }; - build::Store(bcx, llval, lldest); - bcx + (bcx, OperandRef { + llval: llval, + ty: operand.ty, + }) } mir::Rvalue::Box(content_ty) => { - let content_ty: Ty<'tcx> = content_ty; + let content_ty: Ty<'tcx> = bcx.monomorphize(&content_ty); let llty = type_of::type_of(bcx.ccx(), content_ty); let llsize = machine::llsize_of(bcx.ccx(), llty); let align = type_of::align_of(bcx.ccx(), content_ty); @@ -204,34 +285,17 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { llsize, llalign, DebugLoc::None); - build::Store(bcx, llval, lldest); - bcx - } - - mir::Rvalue::Aggregate(_, ref operands) => { - for (i, operand) in operands.iter().enumerate() { - let lldest_i = build::GEPi(bcx, lldest, &[0, i]); - self.trans_operand_into(bcx, lldest_i, operand); - } - bcx + (bcx, OperandRef { + llval: llval, + ty: box_ty, + }) } - mir::Rvalue::Slice { ref input, from_start, from_end } => { - let ccx = bcx.ccx(); - let input = self.trans_lvalue(bcx, input); - let (llbase, lllen) = tvec::get_base_and_len(bcx, - input.llval, - input.ty.to_ty(bcx.tcx())); - let llbase1 = build::GEPi(bcx, llbase, &[from_start]); - let adj = common::C_uint(ccx, from_start + from_end); - let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); - build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR])); - build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA])); - bcx - } - - mir::Rvalue::InlineAsm(inline_asm) => { - asm::trans_inline_asm(bcx, inline_asm) + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) | + mir::Rvalue::Slice { .. } | + mir::Rvalue::InlineAsm(..) => { + bcx.tcx().sess.bug(&format!("cannot generate operand from rvalue {:?}", rvalue)); } } } diff --git a/src/librustc_trans/trans/mir/statement.rs b/src/librustc_trans/trans/mir/statement.rs index 17a20fb817c89..95ff049836eb4 100644 --- a/src/librustc_trans/trans/mir/statement.rs +++ b/src/librustc_trans/trans/mir/statement.rs @@ -15,6 +15,7 @@ use trans::debuginfo::DebugLoc; use trans::glue; use super::MirContext; +use super::TempRef; impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { pub fn trans_statement(&mut self, @@ -25,9 +26,30 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match statement.kind { mir::StatementKind::Assign(ref lvalue, ref rvalue) => { - let tr_dest = self.trans_lvalue(bcx, lvalue); - self.trans_rvalue(bcx, tr_dest.llval, rvalue); - bcx + match *lvalue { + mir::Lvalue::Temp(index) => { + let index = index as usize; + match self.temps[index as usize] { + TempRef::Lvalue(tr_dest) => { + self.trans_rvalue(bcx, tr_dest.llval, rvalue) + } + TempRef::Operand(None) => { + let (bcx, operand) = self.trans_rvalue_operand(bcx, rvalue); + self.temps[index] = TempRef::Operand(Some(operand)); + bcx + } + TempRef::Operand(Some(_)) => { + bcx.tcx().sess.span_bug( + statement.span, + &format!("operand {:?} already assigned", rvalue)); + } + } + } + _ => { + let tr_dest = self.trans_lvalue(bcx, lvalue); + self.trans_rvalue(bcx, tr_dest.llval, rvalue) + } + } } mir::StatementKind::Drop(mir::DropKind::Deep, ref lvalue) => { From 61e5b6dfdbb34d9569ebddc6af09cb5a5beb605a Mon Sep 17 00:00:00 2001 From: Seo Sanghyeon Date: Tue, 3 Nov 2015 19:04:36 +0900 Subject: [PATCH 24/53] Warn unused_assignments for arguments --- src/librustc/middle/liveness.rs | 20 ++++++++++++++++---- src/test/compile-fail/liveness-dead.rs | 10 ++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 3b56597d353a3..b25ad66fd1fa5 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -1555,7 +1555,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // Ignore unused self. let name = path1.node; if name != special_idents::self_.name { - self.warn_about_unused(sp, p_id, entry_ln, var); + if !self.warn_about_unused(sp, p_id, entry_ln, var) { + if self.live_on_entry(entry_ln, var).is_none() { + self.report_dead_assign(p_id, sp, var, true); + } + } } }) } @@ -1609,11 +1613,19 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { ln: LiveNode, var: Variable) { if self.live_on_exit(ln, var).is_none() { - let r = self.should_warn(var); - if let Some(name) = r { + self.report_dead_assign(id, sp, var, false); + } + } + + fn report_dead_assign(&self, id: NodeId, sp: Span, var: Variable, is_argument: bool) { + if let Some(name) = self.should_warn(var) { + if is_argument { + self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, + format!("value passed to `{}` is never read", name)); + } else { self.ir.tcx.sess.add_lint(lint::builtin::UNUSED_ASSIGNMENTS, id, sp, format!("value assigned to `{}` is never read", name)); } } } - } +} diff --git a/src/test/compile-fail/liveness-dead.rs b/src/test/compile-fail/liveness-dead.rs index dc7b0fc4fd0f2..ddd8fc68c43a3 100644 --- a/src/test/compile-fail/liveness-dead.rs +++ b/src/test/compile-fail/liveness-dead.rs @@ -27,4 +27,14 @@ fn f3() { x = 4; //~ ERROR: value assigned to `x` is never read } +fn f4(mut x: i32) { //~ ERROR: value passed to `x` is never read + x = 4; + x.clone(); +} + +fn f5(mut x: i32) { + x.clone(); + x = 4; //~ ERROR: value assigned to `x` is never read +} + fn main() {} From 7690ec89ffeac4b4537e71c980d65ead9177d76c Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Tue, 3 Nov 2015 04:26:45 +0000 Subject: [PATCH 25/53] libstd: implement From<&Path|PathBuf> for Cow --- src/libstd/path.rs | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 0559849f6a647..b3f755a60a5be 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1166,6 +1166,22 @@ impl<'a> IntoCow<'a, Path> for &'a Path { } } +#[stable(feature = "cow_from_path", since = "1.6.0")] +impl<'a> From<&'a Path> for Cow<'a, Path> { + #[inline] + fn from(s: &'a Path) -> Cow<'a, Path> { + Cow::Borrowed(s) + } +} + +#[stable(feature = "cow_from_path", since = "1.6.0")] +impl<'a> From for Cow<'a, Path> { + #[inline] + fn from(s: PathBuf) -> Cow<'a, Path> { + Cow::Owned(s) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl ToOwned for Path { type Owned = PathBuf; @@ -2002,6 +2018,26 @@ mod tests { assert_eq!(static_cow_path, owned_cow_path); } + #[test] + fn into() { + use borrow::Cow; + + let static_path = Path::new("/home/foo"); + let static_cow_path: Cow<'static, Path> = static_path.into(); + let pathbuf = PathBuf::from("/home/foo"); + + { + let path: &Path = &pathbuf; + let borrowed_cow_path: Cow = path.into(); + + assert_eq!(static_cow_path, borrowed_cow_path); + } + + let owned_cow_path: Cow<'static, Path> = pathbuf.into(); + + assert_eq!(static_cow_path, owned_cow_path); + } + #[test] #[cfg(unix)] pub fn test_decompositions_unix() { From 544b06d455a067ab54a850e34bdc7794f23c6734 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 06:33:59 -0500 Subject: [PATCH 26/53] Add a MIR visitor --- src/librustc_mir/lib.rs | 1 + src/librustc_mir/visit.rs | 239 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 240 insertions(+) create mode 100644 src/librustc_mir/visit.rs diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs index 5c52dfe2bd673..ed5df21d91193 100644 --- a/src/librustc_mir/lib.rs +++ b/src/librustc_mir/lib.rs @@ -35,4 +35,5 @@ mod hair; pub mod repr; mod graphviz; pub mod tcx; +pub mod visit; diff --git a/src/librustc_mir/visit.rs b/src/librustc_mir/visit.rs new file mode 100644 index 0000000000000..b4d6075d0adb7 --- /dev/null +++ b/src/librustc_mir/visit.rs @@ -0,0 +1,239 @@ +// Copyright 2012-2014 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 rustc::middle::ty::Region; +use repr::*; + +pub trait Visitor<'tcx> { + // Override these, and call `self.super_xxx` to revert back to the + // default behavior. + + fn visit_mir(&mut self, mir: &Mir<'tcx>) { + self.super_mir(mir); + } + + fn visit_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + self.super_basic_block_data(block, data); + } + + fn visit_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) { + self.super_statement(block, statement); + } + + fn visit_assign(&mut self, block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { + self.super_assign(block, lvalue, rvalue); + } + + fn visit_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) { + self.super_terminator(block, terminator); + } + + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + self.super_rvalue(rvalue); + } + + fn visit_operand(&mut self, operand: &Operand<'tcx>) { + self.super_operand(operand); + } + + fn visit_lvalue(&mut self, lvalue: &Lvalue<'tcx>, context: LvalueContext) { + self.super_lvalue(lvalue, context); + } + + fn visit_branch(&mut self, source: BasicBlock, target: BasicBlock) { + self.super_branch(source, target); + } + + fn visit_constant(&mut self, constant: &Constant<'tcx>) { + self.super_constant(constant); + } + + // The `super_xxx` methods comprise the default behavior and are + // not meant to be overidden. + + fn super_mir(&mut self, mir: &Mir<'tcx>) { + for block in mir.all_basic_blocks() { + let data = mir.basic_block_data(block); + self.visit_basic_block_data(block, data); + } + } + + fn super_basic_block_data(&mut self, block: BasicBlock, data: &BasicBlockData<'tcx>) { + for statement in &data.statements { + self.visit_statement(block, statement); + } + self.visit_terminator(block, &data.terminator); + } + + fn super_statement(&mut self, block: BasicBlock, statement: &Statement<'tcx>) { + match statement.kind { + StatementKind::Assign(ref lvalue, ref rvalue) => { + self.visit_assign(block, lvalue, rvalue); + } + StatementKind::Drop(_, ref lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Drop); + } + } + } + + fn super_assign(&mut self, _block: BasicBlock, lvalue: &Lvalue<'tcx>, rvalue: &Rvalue<'tcx>) { + self.visit_lvalue(lvalue, LvalueContext::Store); + self.visit_rvalue(rvalue); + } + + fn super_terminator(&mut self, block: BasicBlock, terminator: &Terminator<'tcx>) { + match *terminator { + Terminator::Goto { target } | + Terminator::Panic { target } => { + self.visit_branch(block, target); + } + + Terminator::If { ref cond, ref targets } => { + self.visit_operand(cond); + for &target in &targets[..] { + self.visit_branch(block, target); + } + } + + Terminator::Switch { ref discr, adt_def: _, ref targets } => { + self.visit_lvalue(discr, LvalueContext::Inspect); + for &target in targets { + self.visit_branch(block, target); + } + } + + Terminator::Diverge | + Terminator::Return => { + } + + Terminator::Call { ref data, ref targets } => { + self.visit_lvalue(&data.destination, LvalueContext::Store); + self.visit_operand(&data.func); + for arg in &data.args { + self.visit_operand(arg); + } + for &target in &targets[..] { + self.visit_branch(block, target); + } + } + } + } + + fn super_rvalue(&mut self, rvalue: &Rvalue<'tcx>) { + match *rvalue { + Rvalue::Use(ref operand) => { + self.visit_operand(operand); + } + + Rvalue::Repeat(ref value, ref len) => { + self.visit_operand(value); + self.visit_operand(len); + } + + Rvalue::Ref(r, bk, ref path) => { + self.visit_lvalue(path, LvalueContext::Borrow { + region: r, + kind: bk + }); + } + + Rvalue::Len(ref path) => { + self.visit_lvalue(path, LvalueContext::Inspect); + } + + Rvalue::Cast(_, ref operand, _) => { + self.visit_operand(operand); + } + + Rvalue::BinaryOp(_, ref lhs, ref rhs) => { + self.visit_operand(lhs); + self.visit_operand(rhs); + } + + Rvalue::UnaryOp(_, ref op) => { + self.visit_operand(op); + } + + Rvalue::Box(_) => { + } + + Rvalue::Aggregate(_, ref operands) => { + for operand in operands { + self.visit_operand(operand); + } + } + + Rvalue::Slice { ref input, from_start, from_end } => { + self.visit_lvalue(input, LvalueContext::Slice { + from_start: from_start, + from_end: from_end, + }); + } + + Rvalue::InlineAsm(_) => { + } + } + } + + fn super_operand(&mut self, operand: &Operand<'tcx>) { + match *operand { + Operand::Consume(ref lvalue) => { + self.visit_lvalue(lvalue, LvalueContext::Consume); + } + Operand::Constant(ref constant) => { + self.visit_constant(constant); + } + } + } + + fn super_lvalue(&mut self, lvalue: &Lvalue<'tcx>, _context: LvalueContext) { + match *lvalue { + Lvalue::Var(_) | + Lvalue::Temp(_) | + Lvalue::Arg(_) | + Lvalue::Static(_) | + Lvalue::ReturnPointer => { + } + Lvalue::Projection(ref proj) => { + self.visit_lvalue(&proj.base, LvalueContext::Projection); + } + } + } + + fn super_branch(&mut self, _source: BasicBlock, _target: BasicBlock) { + } + + fn super_constant(&mut self, _constant: &Constant<'tcx>) { + } +} + +#[derive(Copy, Clone, Debug)] +pub enum LvalueContext { + // Appears as LHS of an assignment or as dest of a call + Store, + + // Being dropped + Drop, + + // Being inspected in some way, like loading a len + Inspect, + + // Being borrowed + Borrow { region: Region, kind: BorrowKind }, + + // Being sliced -- this should be same as being borrowed, probably + Slice { from_start: usize, from_end: usize }, + + // Used as base for another lvalue, e.g. `x` in `x.y` + Projection, + + // Consumed as part of an operand + Consume, +} From d9df16bf61b2b20899c2ffeb9ea406a481f572c6 Mon Sep 17 00:00:00 2001 From: Toby Scrace Date: Tue, 3 Nov 2015 11:46:05 +0000 Subject: [PATCH 27/53] Fix #29533 This replaces usage of the (missing) `fatal!` macro with `panic!`. --- src/doc/trpl/error-handling.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 56dfa17b4e3f2..b74aaef927d88 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -2074,7 +2074,7 @@ tweak the case analysis in `main`: ```rust,ignore match search(&args.arg_data_path, &args.arg_city) { Err(CliError::NotFound) if args.flag_quiet => process::exit(1), - Err(err) => fatal!("{}", err), + Err(err) => panic!("{}", err), Ok(pops) => for pop in pops { println!("{}, {}: {:?}", pop.city, pop.country, pop.count); } From bf7c92038e56cfc66aebb9628e43150587fc8244 Mon Sep 17 00:00:00 2001 From: Bruno Tavares Date: Tue, 3 Nov 2015 10:20:45 -0200 Subject: [PATCH 28/53] Closes #24954 --- src/test/run-pass/issue-24954.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 src/test/run-pass/issue-24954.rs diff --git a/src/test/run-pass/issue-24954.rs b/src/test/run-pass/issue-24954.rs new file mode 100644 index 0000000000000..f525274a1dfca --- /dev/null +++ b/src/test/run-pass/issue-24954.rs @@ -0,0 +1,22 @@ +// 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. + +macro_rules! foo { + ($y:expr) => ({ + $y = 2; + }) +} + +#[allow(unused_variables)] +#[allow(unused_assignments)] +fn main() { + let mut x = 1; + foo!(x); +} From b0ca03923359afc8df92a802b7cc1476a72fb2d0 Mon Sep 17 00:00:00 2001 From: Jake Goulding Date: Tue, 3 Nov 2015 08:25:56 -0500 Subject: [PATCH 29/53] Mention what iterator terminators do with an empty iterator --- src/libcore/iter.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/libcore/iter.rs b/src/libcore/iter.rs index 262bfd5de992a..c7d01b4ec2e40 100644 --- a/src/libcore/iter.rs +++ b/src/libcore/iter.rs @@ -1565,6 +1565,8 @@ pub trait Iterator { /// as soon as it finds a `false`, given that no matter what else happens, /// the result will also be `false`. /// + /// An empty iterator returns `true`. + /// /// # Examples /// /// Basic usage: @@ -1613,6 +1615,8 @@ pub trait Iterator { /// as soon as it finds a `true`, given that no matter what else happens, /// the result will also be `true`. /// + /// An empty iterator returns `false`. + /// /// # Examples /// /// Basic usage: @@ -2071,6 +2075,8 @@ pub trait Iterator { /// /// Takes each element, adds them together, and returns the result. /// + /// An empty iterator returns the zero value of the type. + /// /// # Examples /// /// Basic usage: @@ -2094,6 +2100,8 @@ pub trait Iterator { /// Iterates over the entire iterator, multiplying all the elements /// + /// An empty iterator returns the one value of the type. + /// /// # Examples /// /// ``` From 6468292c35d3ca556decce809d1b79c4f8b250e2 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Mon, 12 Oct 2015 02:14:55 +0530 Subject: [PATCH 30/53] Fix ICE with unresolved associated items in closures (fixes #28971) --- src/librustc/middle/mem_categorization.rs | 13 ++++++++++- src/test/compile-fail/issue-28971.rs | 27 +++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 src/test/compile-fail/issue-28971.rs diff --git a/src/librustc/middle/mem_categorization.rs b/src/librustc/middle/mem_categorization.rs index 1fcd6e92305f5..f3d67feb5ca80 100644 --- a/src/librustc/middle/mem_categorization.rs +++ b/src/librustc/middle/mem_categorization.rs @@ -1196,7 +1196,18 @@ impl<'t, 'a,'tcx> MemCategorizationContext<'t, 'a, 'tcx> { (*op)(self, cmt.clone(), pat); - let opt_def = self.tcx().def_map.borrow().get(&pat.id).map(|d| d.full_def()); + let opt_def = if let Some(path_res) = self.tcx().def_map.borrow().get(&pat.id) { + if path_res.depth != 0 { + // Since patterns can be associated constants + // which are resolved during typeck, we might have + // some unresolved patterns reaching this stage + // without aborting + return Err(()); + } + Some(path_res.full_def()) + } else { + None + }; // Note: This goes up here (rather than within the PatEnum arm // alone) because struct patterns can refer to struct types or diff --git a/src/test/compile-fail/issue-28971.rs b/src/test/compile-fail/issue-28971.rs new file mode 100644 index 0000000000000..1d14b71a40e4f --- /dev/null +++ b/src/test/compile-fail/issue-28971.rs @@ -0,0 +1,27 @@ +// Copyright 2012-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. + +// This should not cause an ICE + +enum Foo { + Bar(u8) +} +fn main(){ + foo(|| { + match Foo::Bar(1) { + Foo::Baz(..) => (), //~ ERROR no associated + _ => (), + } + }); +} + +fn foo(f: F) where F: FnMut() { + f(); +} From 1805e5fb487fb3d1e6b8dc71b3983ac91b62c511 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 3 Nov 2015 15:19:46 +0000 Subject: [PATCH 31/53] Allow indirect operands to be used as inputs for inline asm --- src/libsyntax/ext/asm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libsyntax/ext/asm.rs b/src/libsyntax/ext/asm.rs index 984e73f85f610..bdfbb7a49330e 100644 --- a/src/libsyntax/ext/asm.rs +++ b/src/libsyntax/ext/asm.rs @@ -139,9 +139,9 @@ pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree]) let (constraint, _str_style) = panictry!(p.parse_str()); - if constraint.starts_with("=") { + if constraint.starts_with("=") && !constraint.contains("*") { cx.span_err(p.last_span, "input operand constraint contains '='"); - } else if constraint.starts_with("+") { + } else if constraint.starts_with("+") && !constraint.contains("*") { cx.span_err(p.last_span, "input operand constraint contains '+'"); } From cc830ef18b3014158715f0fd5635a179c5bd7844 Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Tue, 3 Nov 2015 04:51:21 +0000 Subject: [PATCH 32/53] libstd: implement PartialEq for PathBuf and Cow --- src/libstd/path.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index b3f755a60a5be..9a5852663cb67 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1909,6 +1909,29 @@ impl<'a> IntoIterator for &'a Path { fn into_iter(self) -> Iter<'a> { self.iter() } } +macro_rules! impl_eq { + ($lhs:ty, $rhs: ty) => { + #[stable(feature = "partialeq_path", since = "1.6.0")] + impl<'a, 'b> PartialEq<$rhs> for $lhs { + #[inline] + fn eq(&self, other: &$rhs) -> bool { ::eq(self, other) } + } + + #[stable(feature = "partialeq_path", since = "1.6.0")] + impl<'a, 'b> PartialEq<$lhs> for $rhs { + #[inline] + fn eq(&self, other: &$lhs) -> bool { ::eq(self, other) } + } + + } +} + +impl_eq!(PathBuf, Path); +impl_eq!(PathBuf, &'a Path); +impl_eq!(Cow<'a, Path>, Path); +impl_eq!(Cow<'a, Path>, &'b Path); +impl_eq!(Cow<'a, Path>, PathBuf); + #[cfg(test)] mod tests { use super::*; @@ -3106,6 +3129,31 @@ mod tests { tfe!("/", "foo", "/", false); } + #[test] + fn test_eq_recievers() { + use borrow::Cow; + + let borrowed: &Path = Path::new("foo/bar"); + let mut owned: PathBuf = PathBuf::new(); + owned.push("foo"); + owned.push("bar"); + let borrowed_cow: Cow = borrowed.into(); + let owned_cow: Cow = owned.clone().into(); + + macro_rules! t { + ($($current:expr),+) => { + $( + assert_eq!($current, borrowed); + assert_eq!($current, owned); + assert_eq!($current, borrowed_cow); + assert_eq!($current, owned_cow); + )+ + } + } + + t!(borrowed, owned, borrowed_cow, owned_cow); + } + #[test] pub fn test_compare() { use hash::{Hash, Hasher, SipHasher}; From f57621535efc5b68d883ef51dc3b324e9ab3d83f Mon Sep 17 00:00:00 2001 From: Kevin Butler Date: Tue, 3 Nov 2015 04:54:32 +0000 Subject: [PATCH 33/53] libcollections: DRY up a PartialEq impl for String --- src/libcollections/string.rs | 21 +++------------------ 1 file changed, 3 insertions(+), 18 deletions(-) diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs index 96a28d3ee3ba3..8d07e2b2018ad 100644 --- a/src/libcollections/string.rs +++ b/src/libcollections/string.rs @@ -963,7 +963,7 @@ impl PartialEq for String { macro_rules! impl_eq { ($lhs:ty, $rhs: ty) => { #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> PartialEq<$rhs> for $lhs { + impl<'a, 'b> PartialEq<$rhs> for $lhs { #[inline] fn eq(&self, other: &$rhs) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] @@ -971,7 +971,7 @@ macro_rules! impl_eq { } #[stable(feature = "rust1", since = "1.0.0")] - impl<'a> PartialEq<$lhs> for $rhs { + impl<'a, 'b> PartialEq<$lhs> for $rhs { #[inline] fn eq(&self, other: &$lhs) -> bool { PartialEq::eq(&self[..], &other[..]) } #[inline] @@ -984,24 +984,9 @@ macro_rules! impl_eq { impl_eq! { String, str } impl_eq! { String, &'a str } impl_eq! { Cow<'a, str>, str } +impl_eq! { Cow<'a, str>, &'b str } impl_eq! { Cow<'a, str>, String } -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> PartialEq<&'b str> for Cow<'a, str> { - #[inline] - fn eq(&self, other: &&'b str) -> bool { PartialEq::eq(&self[..], &other[..]) } - #[inline] - fn ne(&self, other: &&'b str) -> bool { PartialEq::ne(&self[..], &other[..]) } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, 'b> PartialEq> for &'b str { - #[inline] - fn eq(&self, other: &Cow<'a, str>) -> bool { PartialEq::eq(&self[..], &other[..]) } - #[inline] - fn ne(&self, other: &Cow<'a, str>) -> bool { PartialEq::ne(&self[..], &other[..]) } -} - #[stable(feature = "rust1", since = "1.0.0")] impl Default for String { #[inline] From 54d85b4f2fb0756c67fe92734403bef2d169a08f Mon Sep 17 00:00:00 2001 From: angelsl Date: Sat, 24 Oct 2015 01:27:23 +0800 Subject: [PATCH 34/53] Update compiler-rt --- src/compiler-rt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler-rt b/src/compiler-rt index 58ab642c30d9f..93d0384373750 160000 --- a/src/compiler-rt +++ b/src/compiler-rt @@ -1 +1 @@ -Subproject commit 58ab642c30d9f97735d5745b5d01781ee199c6ae +Subproject commit 93d0384373750b52996fd7f8249adaae39f562d8 From 26db71783f5611ed2d7898e9a4b08c1651eb9bdc Mon Sep 17 00:00:00 2001 From: Michael Layzell Date: Tue, 3 Nov 2015 13:03:36 -0500 Subject: [PATCH 35/53] Correct incorrect assertion in VecDeque::wrap_copy --- src/libcollections/vec_deque.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/libcollections/vec_deque.rs b/src/libcollections/vec_deque.rs index 937ace00fdcca..67db0227cbee9 100644 --- a/src/libcollections/vec_deque.rs +++ b/src/libcollections/vec_deque.rs @@ -148,9 +148,9 @@ impl VecDeque { /// Copies a contiguous block of memory len long from src to dst #[inline] unsafe fn copy(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + debug_assert!(dst + len <= self.cap(), "cpy dst={} src={} len={} cap={}", dst, src, len, self.cap()); - debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + debug_assert!(src + len <= self.cap(), "cpy dst={} src={} len={} cap={}", dst, src, len, self.cap()); ptr::copy( self.ptr().offset(src as isize), @@ -161,9 +161,9 @@ impl VecDeque { /// Copies a contiguous block of memory len long from src to dst #[inline] unsafe fn copy_nonoverlapping(&self, dst: usize, src: usize, len: usize) { - debug_assert!(dst + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + debug_assert!(dst + len <= self.cap(), "cno dst={} src={} len={} cap={}", dst, src, len, self.cap()); - debug_assert!(src + len <= self.cap(), "dst={} src={} len={} cap={}", dst, src, len, + debug_assert!(src + len <= self.cap(), "cno dst={} src={} len={} cap={}", dst, src, len, self.cap()); ptr::copy_nonoverlapping( self.ptr().offset(src as isize), @@ -175,9 +175,11 @@ impl VecDeque { /// (abs(dst - src) + len) must be no larger than cap() (There must be at /// most one continuous overlapping region between src and dest). unsafe fn wrap_copy(&self, dst: usize, src: usize, len: usize) { - debug_assert!( - (if src <= dst { dst - src } else { src - dst }) + len <= self.cap(), - "dst={} src={} len={} cap={}", dst, src, len, self.cap()); + #[allow(dead_code)] + fn diff(a: usize, b: usize) -> usize {if a <= b {b - a} else {a - b}} + debug_assert!(cmp::min(diff(dst, src), + self.cap() - diff(dst, src)) + len <= self.cap(), + "wrc dst={} src={} len={} cap={}", dst, src, len, self.cap()); if src == dst || len == 0 { return } From 59c5191c211711c8f51daa4911b1b734393a4011 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Tue, 3 Nov 2015 18:13:03 +0000 Subject: [PATCH 36/53] Add test for inline asm indirect memory operands --- src/test/run-pass/asm-indirect-memory.rs | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/test/run-pass/asm-indirect-memory.rs diff --git a/src/test/run-pass/asm-indirect-memory.rs b/src/test/run-pass/asm-indirect-memory.rs new file mode 100644 index 0000000000000..80fd548dfe354 --- /dev/null +++ b/src/test/run-pass/asm-indirect-memory.rs @@ -0,0 +1,39 @@ +// 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(asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn read(ptr: &u32) -> u32 { + let out: u32; + unsafe { + asm!("mov $1, $0" : "=r" (out) : "*m" (ptr)); + } + out +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn write(ptr: &mut u32, val: u32) { + unsafe { + asm!("mov $1, $0" :: "=*m" (ptr), "r" (val)); + } +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn main() { + let a = 1; + let mut b = 2; + assert_eq!(read(&a), 1); + write(&mut b, 3); + assert_eq!(b, 3); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +pub fn main() {} From ca04855a06d1b0c436ee1b931653306ef7ad7e18 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Tue, 3 Nov 2015 20:44:23 +0200 Subject: [PATCH 37/53] resolve: don't speculatively create freevars when resolving Fixes #29522 --- src/librustc_resolve/lib.rs | 300 +++++++++--------- src/test/run-pass/issue-29522.rs | 25 ++ src/test/run-pass/resolve-pseudo-shadowing.rs | 20 ++ 3 files changed, 194 insertions(+), 151 deletions(-) create mode 100644 src/test/run-pass/issue-29522.rs create mode 100644 src/test/run-pass/resolve-pseudo-shadowing.rs diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 106591724a798..882283ba06fd3 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -53,7 +53,7 @@ use rustc::front::map as hir_map; use rustc::session::Session; use rustc::lint; use rustc::metadata::csearch; -use rustc::metadata::decoder::{DefLike, DlDef, DlField, DlImpl}; +use rustc::metadata::decoder::{DefLike, DlDef}; use rustc::middle::def::*; use rustc::middle::def_id::DefId; use rustc::middle::pat_util::pat_bindings_hygienic; @@ -652,6 +652,21 @@ impl Rib { } } +/// A definition along with the index of the rib it was found on +struct LocalDef { + ribs: Option<(Namespace, usize)>, + def: Def +} + +impl LocalDef { + fn from_def(def: Def) -> Self { + LocalDef { + ribs: None, + def: def + } + } +} + /// The link from a module up to its nearest parent node. #[derive(Clone,Debug)] enum ParentLink { @@ -1954,116 +1969,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.current_module = orig_module; } - /// Wraps the given definition in the appropriate number of `DefUpvar` - /// wrappers. - fn upvarify(&self, - ribs: &[Rib], - def_like: DefLike, - span: Span) - -> Option { - let mut def = match def_like { - DlDef(def) => def, - _ => return Some(def_like) - }; - match def { - DefUpvar(..) => { - self.session.span_bug(span, - &format!("unexpected {:?} in bindings", def)) - } - DefLocal(_, node_id) => { - for rib in ribs { - match rib.kind { - NormalRibKind => { - // Nothing to do. Continue. - } - ClosureRibKind(function_id) => { - let prev_def = def; - let node_def_id = self.ast_map.local_def_id(node_id); - - let mut seen = self.freevars_seen.borrow_mut(); - let seen = seen.entry(function_id).or_insert_with(|| NodeMap()); - if let Some(&index) = seen.get(&node_id) { - def = DefUpvar(node_def_id, node_id, index, function_id); - continue; - } - let mut freevars = self.freevars.borrow_mut(); - let vec = freevars.entry(function_id) - .or_insert_with(|| vec![]); - let depth = vec.len(); - vec.push(Freevar { def: prev_def, span: span }); - - def = DefUpvar(node_def_id, node_id, depth, function_id); - seen.insert(node_id, depth); - } - ItemRibKind | MethodRibKind => { - // This was an attempt to access an upvar inside a - // named function item. This is not allowed, so we - // report an error. - resolve_error( - self, - span, - ResolutionError::CannotCaptureDynamicEnvironmentInFnItem - ); - return None; - } - ConstantItemRibKind => { - // Still doesn't deal with upvars - resolve_error( - self, - span, - ResolutionError::AttemptToUseNonConstantValueInConstant - ); - return None; - } - } - } - } - DefTyParam(..) | DefSelfTy(..) => { - for rib in ribs { - match rib.kind { - NormalRibKind | MethodRibKind | ClosureRibKind(..) => { - // Nothing to do. Continue. - } - ItemRibKind => { - // This was an attempt to use a type parameter outside - // its scope. - - resolve_error(self, - span, - ResolutionError::TypeParametersFromOuterFunction); - return None; - } - ConstantItemRibKind => { - // see #9186 - resolve_error(self, span, ResolutionError::OuterTypeParameterContext); - return None; - } - } - } - } - _ => {} - } - Some(DlDef(def)) - } - - /// Searches the current set of local scopes and - /// applies translations for closures. - fn search_ribs(&self, - ribs: &[Rib], - name: Name, - span: Span) - -> Option { - // FIXME #4950: Try caching? - - for (i, rib) in ribs.iter().enumerate().rev() { - if let Some(def_like) = rib.bindings.get(&name).cloned() { - return self.upvarify(&ribs[i + 1..], def_like, span); - } - } - - None - } - /// Searches the current set of local scopes for labels. /// Stops after meeting a closure. fn search_label(&self, name: Name) -> Option { @@ -3123,19 +3028,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Try to find a path to an item in a module. - let unqualified_def = - self.resolve_identifier(segments.last().unwrap().identifier, - namespace, - check_ribs, - span); + let unqualified_def = self.resolve_identifier( + segments.last().unwrap().identifier, + namespace, check_ribs); if segments.len() <= 1 { - return unqualified_def.map(mk_res); + return unqualified_def + .and_then(|def| self.adjust_local_def(def, span)) + .map(|def| { + PathResolution::new(def, LastMod(AllPublic), path_depth) + }); } let def = self.resolve_module_relative_path(span, segments, namespace); match (def, unqualified_def) { - (Some((ref d, _)), Some((ref ud, _))) if *d == *ud => { + (Some((ref d, _)), Some(ref ud)) if *d == ud.def => { self.session .add_lint(lint::builtin::UNUSED_QUALIFICATIONS, id, span, @@ -3147,31 +3054,119 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { def.map(mk_res) } - // Resolve a single identifier. + // Resolve a single identifier fn resolve_identifier(&mut self, identifier: Ident, namespace: Namespace, - check_ribs: bool, - span: Span) - -> Option<(Def, LastPrivate)> { + check_ribs: bool) + -> Option { // First, check to see whether the name is a primitive type. if namespace == TypeNS { if let Some(&prim_ty) = self.primitive_type_table .primitive_types .get(&identifier.name) { - return Some((DefPrimTy(prim_ty), LastMod(AllPublic))); + return Some(LocalDef::from_def(DefPrimTy(prim_ty))); } } if check_ribs { if let Some(def) = self.resolve_identifier_in_local_ribs(identifier, - namespace, - span) { - return Some((def, LastMod(AllPublic))); + namespace) { + return Some(def); } } self.resolve_item_by_name_in_lexical_scope(identifier.name, namespace) + .map(LocalDef::from_def) + } + + // Resolve a local definition, potentially adjusting for closures. + fn adjust_local_def(&self, local_def: LocalDef, span: Span) -> Option { + let ribs = match local_def.ribs { + Some((TypeNS, i)) => &self.type_ribs[i+1..], + Some((ValueNS, i)) => &self.value_ribs[i+1..], + _ => &[] as &[_] + }; + let mut def = local_def.def; + match def { + DefUpvar(..) => { + self.session.span_bug(span, + &format!("unexpected {:?} in bindings", def)) + } + DefLocal(_, node_id) => { + for rib in ribs { + match rib.kind { + NormalRibKind => { + // Nothing to do. Continue. + } + ClosureRibKind(function_id) => { + let prev_def = def; + let node_def_id = self.ast_map.local_def_id(node_id); + + let mut seen = self.freevars_seen.borrow_mut(); + let seen = seen.entry(function_id).or_insert_with(|| NodeMap()); + if let Some(&index) = seen.get(&node_id) { + def = DefUpvar(node_def_id, node_id, index, function_id); + continue; + } + let mut freevars = self.freevars.borrow_mut(); + let vec = freevars.entry(function_id) + .or_insert_with(|| vec![]); + let depth = vec.len(); + vec.push(Freevar { def: prev_def, span: span }); + + def = DefUpvar(node_def_id, node_id, depth, function_id); + seen.insert(node_id, depth); + } + ItemRibKind | MethodRibKind => { + // This was an attempt to access an upvar inside a + // named function item. This is not allowed, so we + // report an error. + resolve_error( + self, + span, + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem + ); + return None; + } + ConstantItemRibKind => { + // Still doesn't deal with upvars + resolve_error( + self, + span, + ResolutionError::AttemptToUseNonConstantValueInConstant + ); + return None; + } + } + } + } + DefTyParam(..) | DefSelfTy(..) => { + for rib in ribs { + match rib.kind { + NormalRibKind | MethodRibKind | ClosureRibKind(..) => { + // Nothing to do. Continue. + } + ItemRibKind => { + // This was an attempt to use a type parameter outside + // its scope. + + resolve_error(self, + span, + ResolutionError::TypeParametersFromOuterFunction); + return None; + } + ConstantItemRibKind => { + // see #9186 + resolve_error(self, span, ResolutionError::OuterTypeParameterContext); + return None; + } + } + } + } + _ => {} + } + return Some(def); } // FIXME #4952: Merge me with resolve_name_in_module? @@ -3364,38 +3359,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn resolve_identifier_in_local_ribs(&mut self, ident: Ident, - namespace: Namespace, - span: Span) - -> Option { + namespace: Namespace) + -> Option { // Check the local set of ribs. - let search_result = match namespace { - ValueNS => { - let renamed = mtwt::resolve(ident); - self.search_ribs(&self.value_ribs, renamed, span) - } - TypeNS => { - let name = ident.name; - self.search_ribs(&self.type_ribs, name, span) - } + let (name, ribs) = match namespace { + ValueNS => (mtwt::resolve(ident), &self.value_ribs), + TypeNS => (ident.name, &self.type_ribs) }; - match search_result { - Some(DlDef(def)) => { - debug!("(resolving path in local ribs) resolved `{}` to local: {:?}", - ident, - def); - Some(def) - } - Some(DlField) | Some(DlImpl(_)) | None => { - None + for (i, rib) in ribs.iter().enumerate().rev() { + if let Some(def_like) = rib.bindings.get(&name).cloned() { + match def_like { + DlDef(def) => { + debug!("(resolving path in local ribs) resolved `{}` to {:?} at {}", + name, def, i); + return Some(LocalDef { + ribs: Some((namespace, i)), + def: def + }); + } + def_like => { + debug!("(resolving path in local ribs) resolved `{}` to pseudo-def {:?}", + name, def_like); + return None; + } + } } } + + None } fn resolve_item_by_name_in_lexical_scope(&mut self, name: Name, namespace: Namespace) - -> Option<(Def, LastPrivate)> { + -> Option { // Check the items. let module = self.current_module.clone(); match self.resolve_item_in_lexical_scope(module, @@ -3409,7 +3407,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving item path by identifier in lexical \ scope) failed to resolve {} after success...", name); - return None; + None } Some(def) => { debug!("(resolving item path in lexical scope) \ @@ -3418,7 +3416,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // This lookup is "all public" because it only searched // for one identifier in the current module (couldn't // have passed through reexports or anything like that. - return Some((def, LastMod(AllPublic))); + Some(def) } } } @@ -3433,7 +3431,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)) } - return None; + None } } } diff --git a/src/test/run-pass/issue-29522.rs b/src/test/run-pass/issue-29522.rs new file mode 100644 index 0000000000000..de7c7aee05530 --- /dev/null +++ b/src/test/run-pass/issue-29522.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. + +// check that we don't accidentally capture upvars just because their name +// occurs in a path + +fn assert_static(_t: T) {} + +mod foo { + pub fn scope() {} +} + +fn main() { + let scope = &mut 0; + assert_static(|| { + foo::scope(); + }); +} diff --git a/src/test/run-pass/resolve-pseudo-shadowing.rs b/src/test/run-pass/resolve-pseudo-shadowing.rs new file mode 100644 index 0000000000000..071279ae7d818 --- /dev/null +++ b/src/test/run-pass/resolve-pseudo-shadowing.rs @@ -0,0 +1,20 @@ +// 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. + +// check that type parameters can't "shadow" qualified paths. + +fn check(_c: Clone) { + fn check2() { + <() as std::clone::Clone>::clone(&()); + } + check2(); +} + +fn main() { check(()); } From 6252af9ce10f522dbd5b58bdbbeff1b3e8464066 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 4 Nov 2015 10:16:06 +1300 Subject: [PATCH 38/53] save-analysis: emit the crate root --- src/librustc_trans/save/dump_csv.rs | 11 ++++++++++- src/librustc_trans/save/recorder.rs | 6 +++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index f6f504e27aefc..3ea631bd7fb67 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -107,8 +107,17 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { } pub fn dump_crate_info(&mut self, name: &str, krate: &ast::Crate) { + let source_file = self.tcx.sess.local_crate_source_file.as_ref(); + let crate_root = match source_file { + Some(source_file) => match source_file.file_name() { + Some(_) => source_file.parent().unwrap().display().to_string(), + None => source_file.display().to_string(), + }, + None => "".to_owned(), + }; + // The current crate. - self.fmt.crate_str(krate.span, name); + self.fmt.crate_str(krate.span, name, &crate_root); // Dump info about all the external crates referenced from this crate. for c in &self.save_ctxt.get_external_crates() { diff --git a/src/librustc_trans/save/recorder.rs b/src/librustc_trans/save/recorder.rs index a32d8b1b761c5..34eb1d282636e 100644 --- a/src/librustc_trans/save/recorder.rs +++ b/src/librustc_trans/save/recorder.rs @@ -198,7 +198,7 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { vec!("name", "crate", "file_name"), false, false), - Crate => ("crate", vec!("name"), true, false), + Crate => ("crate", vec!("name", "crate_root"), true, false), FnCall => ("fn_call", vec!("refid", "refidcrate", "qualname", "scopeid"), true, @@ -658,8 +658,8 @@ impl<'a, 'tcx: 'a> FmtStrs<'a, 'tcx> { self.check_and_record(Typedef, span, sub_span, svec!(id, qualname, value)); } - pub fn crate_str(&mut self, span: Span, name: &str) { - self.record_with_span(Crate, span, span, svec!(name)); + pub fn crate_str(&mut self, span: Span, name: &str, crate_root: &str) { + self.record_with_span(Crate, span, span, svec!(name, crate_root)); } pub fn external_crate_str(&mut self, span: Span, name: &str, num: ast::CrateNum) { From 6a5b263503dce838c2a09619171b409c9f11bb9f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 06:35:09 -0500 Subject: [PATCH 39/53] Add (and use) an analysis to determine which temps can forgo an alloca. --- src/librustc_trans/trans/mir/analyze.rs | 115 ++++++++++++++++++++++++ src/librustc_trans/trans/mir/mod.rs | 4 +- src/librustc_trans/trans/mir/operand.rs | 22 ++++- src/librustc_trans/trans/mir/rvalue.rs | 44 ++++----- 4 files changed, 160 insertions(+), 25 deletions(-) create mode 100644 src/librustc_trans/trans/mir/analyze.rs diff --git a/src/librustc_trans/trans/mir/analyze.rs b/src/librustc_trans/trans/mir/analyze.rs new file mode 100644 index 0000000000000..acf6e53468ef5 --- /dev/null +++ b/src/librustc_trans/trans/mir/analyze.rs @@ -0,0 +1,115 @@ +// Copyright 2012-2014 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. + +//! An analysis to determine which temporaries require allocas and +//! which do not. + +use rustc_data_structures::fnv::FnvHashSet; +use rustc_mir::repr as mir; +use rustc_mir::visit::{Visitor, LvalueContext}; +use trans::common::{self, Block}; +use super::rvalue; + +pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>, + mir: &mir::Mir<'tcx>) + -> FnvHashSet { + let mut analyzer = TempAnalyzer::new(); + + analyzer.visit_mir(mir); + + for (index, temp_decl) in mir.temp_decls.iter().enumerate() { + let ty = bcx.monomorphize(&temp_decl.ty); + debug!("temp {:?} has type {:?}", index, ty); + if + ty.is_scalar() || + ty.is_unique() || + ty.is_region_ptr() || + ty.is_simd() + { + // These sorts of types are immediates that we can store + // in an ValueRef without an alloca. + assert!(common::type_is_immediate(bcx.ccx(), ty)); + } else { + // These sorts of types require an alloca. Note that + // type_is_immediate() may *still* be true, particularly + // for newtypes, but we currently force some types + // (e.g. structs) into an alloca unconditionally, just so + // that we don't have to deal with having two pathways + // (gep vs getvalue etc). + analyzer.mark_as_lvalue(index); + } + } + + analyzer.lvalue_temps +} + +struct TempAnalyzer { + lvalue_temps: FnvHashSet, +} + +impl TempAnalyzer { + fn new() -> TempAnalyzer { + TempAnalyzer { lvalue_temps: FnvHashSet() } + } + + fn mark_as_lvalue(&mut self, temp: usize) { + debug!("marking temp {} as lvalue", temp); + self.lvalue_temps.insert(temp); + } +} + +impl<'tcx> Visitor<'tcx> for TempAnalyzer { + fn visit_assign(&mut self, + block: mir::BasicBlock, + lvalue: &mir::Lvalue<'tcx>, + rvalue: &mir::Rvalue<'tcx>) { + debug!("visit_assign(block={:?}, lvalue={:?}, rvalue={:?})", block, lvalue, rvalue); + + match *lvalue { + mir::Lvalue::Temp(index) => { + if !rvalue::rvalue_creates_operand(rvalue) { + self.mark_as_lvalue(index as usize); + } + } + _ => { + self.visit_lvalue(lvalue, LvalueContext::Store); + } + } + + self.visit_rvalue(rvalue); + } + + fn visit_lvalue(&mut self, + lvalue: &mir::Lvalue<'tcx>, + context: LvalueContext) { + debug!("visit_lvalue(lvalue={:?}, context={:?})", lvalue, context); + + match *lvalue { + mir::Lvalue::Temp(index) => { + match context { + LvalueContext::Consume => { + } + LvalueContext::Store | + LvalueContext::Drop | + LvalueContext::Inspect | + LvalueContext::Borrow { .. } | + LvalueContext::Slice { .. } | + LvalueContext::Projection => { + self.mark_as_lvalue(index as usize); + } + } + } + _ => { + } + } + + self.super_lvalue(lvalue, context); + } +} diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 760018b4313c8..353ac2e5f79ca 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -10,7 +10,6 @@ use libc::c_uint; use llvm::{self, ValueRef}; -use rustc_data_structures::fnv::FnvHashSet; use rustc_mir::repr as mir; use rustc_mir::tcx::LvalueTy; use trans::base; @@ -79,7 +78,7 @@ pub fn trans_mir<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>) { // Analyze the temps to determine which must be lvalues // FIXME - let lvalue_temps: FnvHashSet = (0..mir.temp_decls.len()).collect(); + let lvalue_temps = analyze::lvalue_temps(bcx, mir); // Allocate variable and temp allocas let vars = mir.var_decls.iter() @@ -183,6 +182,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>, .collect() } +mod analyze; mod block; mod constant; mod lvalue; diff --git a/src/librustc_trans/trans/mir/operand.rs b/src/librustc_trans/trans/mir/operand.rs index 786b84ae80759..a0308032ac07b 100644 --- a/src/librustc_trans/trans/mir/operand.rs +++ b/src/librustc_trans/trans/mir/operand.rs @@ -16,8 +16,9 @@ use trans::build; use trans::common::Block; use trans::datum; -use super::MirContext; +use super::{MirContext, TempRef}; +#[derive(Copy, Clone)] pub struct OperandRef<'tcx> { // This will be "indirect" if `appropriate_rvalue_mode` returns // ByRef, and otherwise ByValue. @@ -37,6 +38,25 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { match *operand { mir::Operand::Consume(ref lvalue) => { + // watch out for temporaries that do not have an + // alloca; they are handled somewhat differently + if let &mir::Lvalue::Temp(index) = lvalue { + match self.temps[index as usize] { + TempRef::Operand(Some(o)) => { + return o; + } + TempRef::Operand(None) => { + bcx.tcx().sess.bug( + &format!("use of {:?} before def", lvalue)); + } + TempRef::Lvalue(..) => { + // use path below + } + } + } + + // for most lvalues, to consume them we just load them + // out from their home let tr_lvalue = self.trans_lvalue(bcx, lvalue); let ty = tr_lvalue.ty.to_ty(bcx.tcx()); debug!("trans_operand: tr_lvalue={} @ {:?}", diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index c82726fd0e577..7c0912592b6fd 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -80,7 +80,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } _ => { - assert!(self.rvalue_creates_operand(rvalue)); + assert!(rvalue_creates_operand(rvalue)); let (bcx, temp) = self.trans_rvalue_operand(bcx, rvalue); build::Store(bcx, temp.llval, lldest); bcx @@ -88,32 +88,12 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } - pub fn rvalue_creates_operand(&self, rvalue: &mir::Rvalue<'tcx>) -> bool { - match *rvalue { - mir::Rvalue::Use(..) | // (*) - mir::Rvalue::Ref(..) | - mir::Rvalue::Len(..) | - mir::Rvalue::Cast(..) | // (*) - mir::Rvalue::BinaryOp(..) | - mir::Rvalue::UnaryOp(..) | - mir::Rvalue::Box(..) => - true, - mir::Rvalue::Repeat(..) | - mir::Rvalue::Aggregate(..) | - mir::Rvalue::Slice { .. } | - mir::Rvalue::InlineAsm(..) => - false, - } - - // (*) this is only true if the type is suitable - } - pub fn trans_rvalue_operand(&mut self, bcx: Block<'bcx, 'tcx>, rvalue: &mir::Rvalue<'tcx>) -> (Block<'bcx, 'tcx>, OperandRef<'tcx>) { - assert!(self.rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); + assert!(rvalue_creates_operand(rvalue), "cannot trans {:?} to operand", rvalue); match *rvalue { mir::Rvalue::Use(ref operand) => { @@ -300,3 +280,23 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { } } } + +pub fn rvalue_creates_operand<'tcx>(rvalue: &mir::Rvalue<'tcx>) -> bool { + match *rvalue { + mir::Rvalue::Use(..) | // (*) + mir::Rvalue::Ref(..) | + mir::Rvalue::Len(..) | + mir::Rvalue::Cast(..) | // (*) + mir::Rvalue::BinaryOp(..) | + mir::Rvalue::UnaryOp(..) | + mir::Rvalue::Box(..) => + true, + mir::Rvalue::Repeat(..) | + mir::Rvalue::Aggregate(..) | + mir::Rvalue::Slice { .. } | + mir::Rvalue::InlineAsm(..) => + false, + } + + // (*) this is only true if the type is suitable +} From 9c9f4be9df863e529b09f195f013710e676fb5c1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 06:44:45 -0500 Subject: [PATCH 40/53] correct typos --- src/librustc_trans/trans/mir/mod.rs | 2 +- src/librustc_trans/trans/mir/rvalue.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index 353ac2e5f79ca..fb652c6dc7e3e 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -159,7 +159,7 @@ fn arg_value_refs<'bcx, 'tcx>(bcx: Block<'bcx, 'tcx>, llarg } else if common::type_is_fat_ptr(tcx, arg_ty) { // we pass fat pointers as two words, but we want to - // represent them internally as a pointer two two words, + // represent them internally as a pointer to two words, // so make an alloca to store them in. let lldata = llvm::get_param(fcx.llfn, idx); let llextra = llvm::get_param(fcx.llfn, idx + 1); diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 7c0912592b6fd..dc73c60c9a077 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -172,7 +172,7 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { // // Note that this is currently duplicated with src/libcore/ops.rs // which does the same thing, and it would be nice to perhaps unify - // these two implementations on day! Also note that we call `fmod` + // these two implementations one day! Also note that we call `fmod` // for both 32 and 64-bit floats because if we emit any FRem // instruction at all then LLVM is capable of optimizing it into a // 32-bit FRem (which we're trying to avoid). From b46c0fc49749affc0fc953e8cdc136f5aff5c1b3 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 15:50:04 -0500 Subject: [PATCH 41/53] address nits from dotdash --- src/librustc_trans/trans/mir/analyze.rs | 4 ++-- src/librustc_trans/trans/mir/mod.rs | 3 +++ src/librustc_trans/trans/mir/rvalue.rs | 10 ++++++++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/librustc_trans/trans/mir/analyze.rs b/src/librustc_trans/trans/mir/analyze.rs index acf6e53468ef5..f5fa897bca631 100644 --- a/src/librustc_trans/trans/mir/analyze.rs +++ b/src/librustc_trans/trans/mir/analyze.rs @@ -30,7 +30,7 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>, if ty.is_scalar() || ty.is_unique() || - ty.is_region_ptr() || + (ty.is_region_ptr() && !common::type_is_fat_ptr(bcx.tcx(), ty)) || ty.is_simd() { // These sorts of types are immediates that we can store @@ -42,7 +42,7 @@ pub fn lvalue_temps<'bcx,'tcx>(bcx: Block<'bcx,'tcx>, // for newtypes, but we currently force some types // (e.g. structs) into an alloca unconditionally, just so // that we don't have to deal with having two pathways - // (gep vs getvalue etc). + // (gep vs extractvalue etc). analyzer.mark_as_lvalue(index); } } diff --git a/src/librustc_trans/trans/mir/mod.rs b/src/librustc_trans/trans/mir/mod.rs index fb652c6dc7e3e..3b018cc132184 100644 --- a/src/librustc_trans/trans/mir/mod.rs +++ b/src/librustc_trans/trans/mir/mod.rs @@ -55,6 +55,9 @@ pub struct MirContext<'bcx, 'tcx:'bcx> { /// - nor should it appear in an lvalue path like `tmp.a` /// - the operand must be defined by an rvalue that can generate immediate /// values + /// + /// Avoiding allocs can also be important for certain intrinsics, + /// notably `expect`. temps: Vec>, /// The arguments to the function; as args are lvalues, these are diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index dc73c60c9a077..94cc7857a14f0 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -20,6 +20,7 @@ use trans::build; use trans::common::{self, Block, Result}; use trans::debuginfo::DebugLoc; use trans::declare; +use trans::expr; use trans::machine; use trans::type_::Type; use trans::type_of; @@ -55,6 +56,9 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { mir::Rvalue::Aggregate(_, ref operands) => { for (i, operand) in operands.iter().enumerate() { + // Note: perhaps this should be StructGep, but + // note that in some cases the values here will + // not be structs but arrays. let lldest_i = build::GEPi(bcx, lldest, &[0, i]); self.trans_operand_into(bcx, lldest_i, operand); } @@ -70,8 +74,10 @@ impl<'bcx, 'tcx> MirContext<'bcx, 'tcx> { let llbase1 = build::GEPi(bcx, llbase, &[from_start]); let adj = common::C_uint(ccx, from_start + from_end); let lllen1 = build::Sub(bcx, lllen, adj, DebugLoc::None); - build::Store(bcx, llbase1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_ADDR])); - build::Store(bcx, lllen1, build::GEPi(bcx, lldest, &[0, abi::FAT_PTR_EXTRA])); + let lladdrdest = expr::get_dataptr(bcx, lldest); + build::Store(bcx, llbase1, lladdrdest); + let llmetadest = expr::get_meta(bcx, lldest); + build::Store(bcx, lllen1, llmetadest); bcx } From e78786315b44037258970ee9187f3fd6f89fc61b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 3 Nov 2015 20:38:02 -0500 Subject: [PATCH 42/53] remove unused import --- src/librustc_trans/trans/mir/rvalue.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/librustc_trans/trans/mir/rvalue.rs b/src/librustc_trans/trans/mir/rvalue.rs index 94cc7857a14f0..ad89ee79de40f 100644 --- a/src/librustc_trans/trans/mir/rvalue.rs +++ b/src/librustc_trans/trans/mir/rvalue.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use back::abi; use llvm::ValueRef; use rustc::middle::ty::Ty; use rustc_front::hir; From 9fe4e962e1fe7a4c1d603d1549800d105ca5941f Mon Sep 17 00:00:00 2001 From: angelsl Date: Sat, 24 Oct 2015 00:31:12 +0800 Subject: [PATCH 43/53] Build compiler-rt/builtins with MSVC --- configure | 46 +++++++++++-------- mk/rt.mk | 39 ++++++++++------ .../compiler-rt-works-on-mingw/Makefile | 17 +++++++ .../compiler-rt-works-on-mingw/foo.cpp | 5 ++ .../compiler-rt-works-on-mingw/foo.rs | 16 +++++++ 5 files changed, 89 insertions(+), 34 deletions(-) create mode 100644 src/test/run-make/compiler-rt-works-on-mingw/Makefile create mode 100644 src/test/run-make/compiler-rt-works-on-mingw/foo.cpp create mode 100644 src/test/run-make/compiler-rt-works-on-mingw/foo.rs diff --git a/configure b/configure index 60d366100f8c2..8caf6abed781b 100755 --- a/configure +++ b/configure @@ -1498,25 +1498,9 @@ do done fi - if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -ne 0 ] + # We need the generator later on for compiler-rt even if LLVM's not built + if [ ${is_msvc} -ne 0 ] then - msg "configuring LLVM for $t with cmake" - - CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF" - if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then - CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" - else - CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" - fi - if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ] - then - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=OFF" - else - CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" - fi - - msg "configuring LLVM with:" - msg "$CMAKE_ARGS" case "$CFG_MSVC_ROOT" in *14.0*) generator="Visual Studio 14 2015" @@ -1538,8 +1522,32 @@ do err "can only build LLVM for x86 platforms" ;; esac + CFG_CMAKE_GENERATOR=$generator + putvar CFG_CMAKE_GENERATOR + fi + + if [ ${do_reconfigure} -ne 0 ] && [ ${is_msvc} -ne 0 ] + then + msg "configuring LLVM for $t with cmake" + + CMAKE_ARGS="-DLLVM_INCLUDE_TESTS=OFF" + if [ -n "$CFG_DISABLE_OPTIMIZE_LLVM" ]; then + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Debug" + else + CMAKE_ARGS="$CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release" + fi + if [ -z "$CFG_ENABLE_LLVM_ASSERTIONS" ] + then + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=OFF" + else + CMAKE_ARGS="$CMAKE_ARGS -DLLVM_ENABLE_ASSERTIONS=ON" + fi + + msg "configuring LLVM with:" + msg "$CMAKE_ARGS" + (cd $LLVM_BUILD_DIR && "$CFG_CMAKE" $CFG_LLVM_SRC_DIR \ - -G "$generator" \ + -G "$CFG_CMAKE_GENERATOR" \ $CMAKE_ARGS) need_ok "LLVM cmake configure failed" fi diff --git a/mk/rt.mk b/mk/rt.mk index 1f60aaed4730b..d8b5aeccdcd44 100644 --- a/mk/rt.mk +++ b/mk/rt.mk @@ -216,22 +216,31 @@ COMPRT_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt) COMPRT_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(COMPRT_NAME_$(1)) COMPRT_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/compiler-rt -# Note that on MSVC-targeting builds we hardwire CC/AR to gcc/ar even though -# we're targeting MSVC. This is because although compiler-rt has a CMake build -# config I can't actually figure out how to use it, so I'm not sure how to use -# cl.exe to build the objects. Additionally, the compiler-rt library when built -# with gcc has the same ABI as cl.exe, so they're largely compatible -COMPRT_CC_$(1) := $$(CC_$(1)) -COMPRT_AR_$(1) := $$(AR_$(1)) -COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) ifeq ($$(findstring msvc,$(1)),msvc) -COMPRT_CC_$(1) := gcc -COMPRT_AR_$(1) := ar -ifeq ($$(findstring i686,$(1)),i686) -COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m32 +$$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) $$(LLVM_CONFIG_$(1)) + @$$(call E, cmake: compiler-rt) + $$(Q)cd "$$(COMPRT_BUILD_DIR_$(1))"; $$(CFG_CMAKE) "$(S)src/compiler-rt" \ + -DCMAKE_BUILD_TYPE=$$(LLVM_BUILD_CONFIG_MODE) \ + -DLLVM_CONFIG_PATH=$$(LLVM_CONFIG_$(1)) \ + -G"$$(CFG_CMAKE_GENERATOR)" + $$(Q)$$(CFG_CMAKE) --build "$$(COMPRT_BUILD_DIR_$(1))" \ + --target lib/builtins/builtins \ + --config $$(LLVM_BUILD_CONFIG_MODE) \ + -- //v:m //nologo + $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/lib/windows/$$(LLVM_BUILD_CONFIG_MODE)/clang_rt.builtins-$$(HOST_$(1)).lib $$@ else -COMPRT_CFLAGS_$(1) := $$(CFG_GCCISH_CFLAGS_$(1)) -m64 -endif +COMPRT_CC_$(1) := $$(CC_$(1)) +COMPRT_AR_$(1) := $$(AR_$(1)) +# We chomp -Werror here because GCC warns about the type signature of +# builtins not matching its own and the build fails. It's a bit hacky, +# but what can we do, we're building libclang-rt using GCC ...... +COMPRT_CFLAGS_$(1) := $$(subst -Werror,,$$(CFG_GCCISH_CFLAGS_$(1))) -std=c99 + +# FreeBSD Clang's packaging is problematic; it doesn't copy unwind.h to +# the standard include directory. This should really be in our changes to +# compiler-rt, but we override the CFLAGS here so there isn't much choice +ifeq ($$(findstring freebsd,$(1)),freebsd) + COMPRT_CFLAGS_$(1) += -I/usr/include/c++/v1 endif $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) @@ -246,7 +255,7 @@ $$(COMPRT_LIB_$(1)): $$(COMPRT_DEPS) $$(MKFILE_DEPS) TargetTriple=$(1) \ triple-builtins $$(Q)cp $$(COMPRT_BUILD_DIR_$(1))/triple/builtins/libcompiler_rt.a $$@ - +endif ################################################################################ # libbacktrace # diff --git a/src/test/run-make/compiler-rt-works-on-mingw/Makefile b/src/test/run-make/compiler-rt-works-on-mingw/Makefile new file mode 100644 index 0000000000000..4ec54f73e67a5 --- /dev/null +++ b/src/test/run-make/compiler-rt-works-on-mingw/Makefile @@ -0,0 +1,17 @@ +-include ../tools.mk + +ifneq (,$(findstring MINGW,$(UNAME))) +ifndef IS_MSVC +all: + g++ foo.cpp -c -o $(TMPDIR)/foo.o + ar crus $(TMPDIR)/libfoo.a $(TMPDIR)/foo.o + $(RUSTC) foo.rs -lfoo -lstdc++ + $(call RUN,foo) +else +all: + +endif +else +all: + +endif diff --git a/src/test/run-make/compiler-rt-works-on-mingw/foo.cpp b/src/test/run-make/compiler-rt-works-on-mingw/foo.cpp new file mode 100644 index 0000000000000..aac3ba4220101 --- /dev/null +++ b/src/test/run-make/compiler-rt-works-on-mingw/foo.cpp @@ -0,0 +1,5 @@ +// ignore-license +extern "C" void foo() { + int *a = new int(3); + delete a; +} diff --git a/src/test/run-make/compiler-rt-works-on-mingw/foo.rs b/src/test/run-make/compiler-rt-works-on-mingw/foo.rs new file mode 100644 index 0000000000000..293f9d582945e --- /dev/null +++ b/src/test/run-make/compiler-rt-works-on-mingw/foo.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. + +extern { fn foo(); } + +pub fn main() { + unsafe { foo(); } + assert_eq!(7f32.powi(3), 343f32); +} From fb2129e043e19e71562c780dd3ef2402e378d52c Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Tue, 3 Nov 2015 23:12:37 -0600 Subject: [PATCH 44/53] Remove the RefCell around freevars and freevars_seen in librustc_resolve --- src/librustc/middle/ty/context.rs | 4 ++-- src/librustc_resolve/lib.rs | 21 ++++++++++----------- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 830232cf373b8..fb0b1c402da86 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -448,7 +448,7 @@ impl<'tcx> ctxt<'tcx> { def_map: DefMap, named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, - freevars: RefCell, + freevars: FreevarMap, region_maps: RegionMaps, lang_items: middle::lang_items::LanguageItems, stability: stability::Index<'tcx>, @@ -481,7 +481,7 @@ impl<'tcx> ctxt<'tcx> { super_predicates: RefCell::new(DefIdMap()), fulfilled_predicates: RefCell::new(traits::FulfilledPredicates::new()), map: map, - freevars: freevars, + freevars: RefCell::new(freevars), tcache: RefCell::new(DefIdMap()), rcache: RefCell::new(FnvHashMap()), tc_cache: RefCell::new(FnvHashMap()), diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 882283ba06fd3..4f602abfbb586 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1151,8 +1151,8 @@ pub struct Resolver<'a, 'tcx:'a> { primitive_type_table: PrimitiveTypeTable, def_map: DefMap, - freevars: RefCell, - freevars_seen: RefCell>>, + freevars: FreevarMap, + freevars_seen: NodeMap>, export_map: ExportMap, trait_map: TraitMap, external_exports: ExternalExports, @@ -1227,8 +1227,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { primitive_type_table: PrimitiveTypeTable::new(), def_map: RefCell::new(NodeMap()), - freevars: RefCell::new(NodeMap()), - freevars_seen: RefCell::new(NodeMap()), + freevars: NodeMap(), + freevars_seen: NodeMap(), export_map: NodeMap(), trait_map: NodeMap(), used_imports: HashSet::new(), @@ -3081,7 +3081,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } // Resolve a local definition, potentially adjusting for closures. - fn adjust_local_def(&self, local_def: LocalDef, span: Span) -> Option { + fn adjust_local_def(&mut self, local_def: LocalDef, span: Span) -> Option { let ribs = match local_def.ribs { Some((TypeNS, i)) => &self.type_ribs[i+1..], Some((ValueNS, i)) => &self.value_ribs[i+1..], @@ -3103,15 +3103,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let prev_def = def; let node_def_id = self.ast_map.local_def_id(node_id); - let mut seen = self.freevars_seen.borrow_mut(); - let seen = seen.entry(function_id).or_insert_with(|| NodeMap()); + let seen = self.freevars_seen.entry(function_id) + .or_insert_with(|| NodeMap()); if let Some(&index) = seen.get(&node_id) { def = DefUpvar(node_def_id, node_id, index, function_id); continue; } - let mut freevars = self.freevars.borrow_mut(); - let vec = freevars.entry(function_id) - .or_insert_with(|| vec![]); + let vec = self.freevars.entry(function_id) + .or_insert_with(|| vec![]); let depth = vec.len(); vec.push(Freevar { def: prev_def, span: span }); @@ -4028,7 +4027,7 @@ fn module_to_string(module: &Module) -> String { pub struct CrateMap { pub def_map: DefMap, - pub freevars: RefCell, + pub freevars: FreevarMap, pub export_map: ExportMap, pub trait_map: TraitMap, pub external_exports: ExternalExports, From 6fb2333d7702356f8960840d41a4763bda074fe7 Mon Sep 17 00:00:00 2001 From: Toby Scrace Date: Wed, 4 Nov 2015 07:42:54 +0000 Subject: [PATCH 45/53] Fix #29542 Reword "Writing the logic" paragraph to prevent `unwrap` being confused for a macro. --- src/doc/trpl/error-handling.md | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index b74aaef927d88..c693cceeac482 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -1605,14 +1605,11 @@ arguments. ## Writing the logic -We're all different in how we write code, but error handling is -usually the last thing we want to think about. This isn't very good -practice for good design, but it can be useful for rapidly -prototyping. In our case, because Rust forces us to be explicit about -error handling, it will also make it obvious what parts of our program -can cause errors. Why? Because Rust will make us call `unwrap`! This -can give us a nice bird's eye view of how we need to approach error -handling. +We all write code differently, but error handling is usually the last thing we +want to think about. This isn't great for the overall design of a program, but +it can be useful for rapid prototyping. Because Rust forces us to be explicit +about error handling (by making us call `unwrap`), it is easy to see which +parts of our program can cause errors. In this case study, the logic is really simple. All we need to do is parse the CSV data given to us and print out a field in matching rows. Let's do it. (Make From e9989d526dd638fd03599d80d2e5658381f4ee68 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 4 Nov 2015 10:19:54 +0100 Subject: [PATCH 46/53] Add note about HashMap::capacity's bounds Fixes #24591 --- src/libstd/collections/hash/map.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 7c6add80337c0..965226f6355c2 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -601,6 +601,9 @@ impl HashMap /// Returns the number of elements the map can hold without reallocating. /// + /// This number is a lower bound; the `HashMap` might be able to hold + /// more, but is guaranteed to be able to hold at least this many. + /// /// # Examples /// /// ``` From 0c93e727c2bc6fd483500db6192e1aff21d2acac Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 4 Nov 2015 10:35:09 +0100 Subject: [PATCH 47/53] Mention multiple impl blocks in TRPL Fixes #29322 --- src/doc/trpl/method-syntax.md | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index d31d823247082..41c134b29f3d1 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -43,8 +43,6 @@ fn main() { This will print `12.566371`. - - We’ve made a `struct` that represents a circle. We then write an `impl` block, and inside it, define a method, `area`. @@ -83,6 +81,35 @@ impl Circle { } ``` +You can use as many `impl` blocks as you’d like. The previous example could +have also been written like this: + +```rust +struct Circle { + x: f64, + y: f64, + radius: f64, +} + +impl Circle { + fn reference(&self) { + println!("taking self by reference!"); + } +} + +impl Circle { + fn mutable_reference(&mut self) { + println!("taking self by mutable reference!"); + } +} + +impl Circle { + fn takes_ownership(self) { + println!("taking ownership of self!"); + } +} +``` + # Chaining method calls So, now we know how to call a method, such as `foo.bar()`. But what about our From a118aa270af592e0745fac4bcbde186830ba41a1 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 4 Nov 2015 12:44:31 +0100 Subject: [PATCH 48/53] Mention [T]::sort is stable in docs Fixes #27322 --- src/libcollections/slice.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libcollections/slice.rs b/src/libcollections/slice.rs index ea4830fc3e6ce..869e7a0b38393 100644 --- a/src/libcollections/slice.rs +++ b/src/libcollections/slice.rs @@ -732,6 +732,8 @@ impl [T] { /// /// This is equivalent to `self.sort_by(|a, b| a.cmp(b))`. /// + /// This is a stable sort. + /// /// # Examples /// /// ```rust From 6b1de254d3f6968c5a9e881fabe555bac2132399 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Wed, 4 Nov 2015 16:56:23 -0800 Subject: [PATCH 49/53] More relnotes tweaks --- RELEASES.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index ada5649ec6e17..54fe87dc65816 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -1,4 +1,4 @@ -Version 1.4.0 (October 2015) +Version 1.4.0 (2015-10-29) ============================ * ~1200 changes, numerous bugfixes @@ -74,7 +74,7 @@ Libraries prelude][pr]. * [`Extend` and `FromIterator` where `T: Copy`][ext] as part of [RFC 839]. This will cause type inferance From 8a69a00941ddb06254abe8633a4f721fd0576266 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Wed, 4 Nov 2015 00:02:22 -0600 Subject: [PATCH 50/53] Unwrap the RefCell around DefMap --- src/librustc/middle/check_static_recursion.rs | 6 ++-- src/librustc/middle/def.rs | 4 +-- src/librustc/middle/pat_util.rs | 30 ++++++++++--------- src/librustc/middle/resolve_lifetime.rs | 5 ++-- src/librustc/middle/ty/context.rs | 4 +-- src/librustc_resolve/lib.rs | 4 +-- src/librustc_trans/trans/_match.rs | 11 +++---- 7 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index 45671367a5c3c..cfd7d3548e065 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -27,7 +27,7 @@ use std::cell::RefCell; struct CheckCrateVisitor<'a, 'ast: 'a> { sess: &'a Session, - def_map: &'a DefMap, + def_map: &'a RefCell, ast_map: &'a ast_map::Map<'ast>, // `discriminant_map` is a cache that associates the `NodeId`s of local // variant definitions with the discriminant expression that applies to @@ -92,7 +92,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { pub fn check_crate<'ast>(sess: &Session, krate: &'ast hir::Crate, - def_map: &DefMap, + def_map: &RefCell, ast_map: &ast_map::Map<'ast>) { let mut visitor = CheckCrateVisitor { sess: sess, @@ -108,7 +108,7 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> { root_span: &'a Span, sess: &'a Session, ast_map: &'a ast_map::Map<'ast>, - def_map: &'a DefMap, + def_map: &'a RefCell, discriminant_map: &'a RefCell>>, idstack: Vec, } diff --git a/src/librustc/middle/def.rs b/src/librustc/middle/def.rs index ef2b918a9f5d7..b1d2418795753 100644 --- a/src/librustc/middle/def.rs +++ b/src/librustc/middle/def.rs @@ -17,8 +17,6 @@ use util::nodemap::NodeMap; use syntax::ast; use rustc_front::hir; -use std::cell::RefCell; - #[derive(Clone, Copy, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug)] pub enum Def { DefFn(DefId, bool /* is_ctor */), @@ -103,7 +101,7 @@ impl PathResolution { } // Definition mapping -pub type DefMap = RefCell>; +pub type DefMap = NodeMap; // This is the replacement export map. It maps a module to all of the exports // within. pub type ExportMap = NodeMap>; diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index c3555273850bc..77ffd0b606ebe 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -18,11 +18,13 @@ use rustc_front::hir; use rustc_front::util::walk_pat; use syntax::codemap::{respan, Span, Spanned, DUMMY_SP}; +use std::cell::RefCell; + pub type PatIdMap = FnvHashMap; // This is used because same-named variables in alternative patterns need to // use the NodeId of their namesake in the first pattern. -pub fn pat_id_map(dm: &DefMap, pat: &hir::Pat) -> PatIdMap { +pub fn pat_id_map(dm: &RefCell, pat: &hir::Pat) -> PatIdMap { let mut map = FnvHashMap(); pat_bindings(dm, pat, |_bm, p_id, _s, path1| { map.insert(path1.node, p_id); @@ -30,7 +32,7 @@ pub fn pat_id_map(dm: &DefMap, pat: &hir::Pat) -> PatIdMap { map } -pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_refutable(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatLit(_) | hir::PatRange(_, _) | hir::PatQPath(..) => true, hir::PatEnum(_, _) | @@ -46,7 +48,7 @@ pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { } } -pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_variant_or_struct(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatEnum(_, _) | hir::PatIdent(_, _, None) | @@ -60,7 +62,7 @@ pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool { } } -pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_const(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => { match dm.borrow().get(&pat.id).map(|d| d.full_def()) { @@ -74,7 +76,7 @@ pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { // Same as above, except that partially-resolved defs cause `false` to be // returned instead of a panic. -pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_resolved_const(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => { match dm.borrow().get(&pat.id) @@ -88,7 +90,7 @@ pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool { } } -pub fn pat_is_binding(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_binding(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(..) => { !pat_is_variant_or_struct(dm, pat) && @@ -98,7 +100,7 @@ pub fn pat_is_binding(dm: &DefMap, pat: &hir::Pat) -> bool { } } -pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_is_binding_or_wild(dm: &RefCell, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(..) => pat_is_binding(dm, pat), hir::PatWild => true, @@ -108,7 +110,7 @@ pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { /// Call `it` on every "binding" in a pattern, e.g., on `a` in /// `match foo() { Some(a) => (), None => () }` -pub fn pat_bindings(dm: &DefMap, pat: &hir::Pat, mut it: I) where +pub fn pat_bindings(dm: &RefCell, pat: &hir::Pat, mut it: I) where I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned), { walk_pat(pat, |p| { @@ -122,7 +124,7 @@ pub fn pat_bindings(dm: &DefMap, pat: &hir::Pat, mut it: I) where }); } -pub fn pat_bindings_hygienic(dm: &DefMap, pat: &hir::Pat, mut it: I) where +pub fn pat_bindings_hygienic(dm: &RefCell, pat: &hir::Pat, mut it: I) where I: FnMut(hir::BindingMode, ast::NodeId, Span, &Spanned), { walk_pat(pat, |p| { @@ -138,7 +140,7 @@ pub fn pat_bindings_hygienic(dm: &DefMap, pat: &hir::Pat, mut it: I) where /// Checks if the pattern contains any patterns that bind something to /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`. -pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool { +pub fn pat_contains_bindings(dm: &RefCell, pat: &hir::Pat) -> bool { let mut contains_bindings = false; walk_pat(pat, |p| { if pat_is_binding(dm, p) { @@ -153,7 +155,7 @@ pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool { /// Checks if the pattern contains any `ref` or `ref mut` bindings, /// and if yes wether its containing mutable ones or just immutables ones. -pub fn pat_contains_ref_binding(dm: &DefMap, pat: &hir::Pat) -> Option { +pub fn pat_contains_ref_binding(dm: &RefCell, pat: &hir::Pat) -> Option { let mut result = None; pat_bindings(dm, pat, |mode, _, _, _| { match mode { @@ -172,7 +174,7 @@ pub fn pat_contains_ref_binding(dm: &DefMap, pat: &hir::Pat) -> Option Option { +pub fn arm_contains_ref_binding(dm: &RefCell, arm: &hir::Arm) -> Option { arm.pats.iter() .filter_map(|pat| pat_contains_ref_binding(dm, pat)) .max_by(|m| match *m { @@ -183,7 +185,7 @@ pub fn arm_contains_ref_binding(dm: &DefMap, arm: &hir::Arm) -> Option bool { +pub fn pat_contains_bindings_or_wild(dm: &RefCell, pat: &hir::Pat) -> bool { let mut contains_bindings = false; walk_pat(pat, |p| { if pat_is_binding_or_wild(dm, p) { @@ -219,7 +221,7 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path { } /// Return variants that are necessary to exist for the pattern to match. -pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { +pub fn necessary_variants(dm: &RefCell, pat: &hir::Pat) -> Vec { let mut variants = vec![]; walk_pat(pat, |p| { match p.node { diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index d9398a1c58cd9..5035ac12a85f7 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -23,6 +23,7 @@ use middle::def::{self, DefMap}; use middle::region; use middle::subst; use middle::ty; +use std::cell::RefCell; use std::fmt; use std::mem::replace; use syntax::ast; @@ -54,7 +55,7 @@ struct LifetimeContext<'a> { sess: &'a Session, named_region_map: &'a mut NamedRegionMap, scope: Scope<'a>, - def_map: &'a DefMap, + def_map: &'a RefCell, // Deep breath. Our representation for poly trait refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` @@ -93,7 +94,7 @@ type Scope<'a> = &'a ScopeChain<'a>; static ROOT_SCOPE: ScopeChain<'static> = RootScope; -pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap { +pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &RefCell) -> NamedRegionMap { let mut named_region_map = NodeMap(); visit::walk_crate(&mut LifetimeContext { sess: sess, diff --git a/src/librustc/middle/ty/context.rs b/src/librustc/middle/ty/context.rs index 2f4e0c58a38bf..d91cac4cc75b9 100644 --- a/src/librustc/middle/ty/context.rs +++ b/src/librustc/middle/ty/context.rs @@ -228,7 +228,7 @@ pub struct ctxt<'tcx> { pub types: CommonTypes<'tcx>, pub sess: &'tcx Session, - pub def_map: DefMap, + pub def_map: RefCell, pub named_region_map: resolve_lifetime::NamedRegionMap, @@ -453,7 +453,7 @@ impl<'tcx> ctxt<'tcx> { /// reference to the context, to allow formatting values that need it. pub fn create_and_enter(s: &'tcx Session, arenas: &'tcx CtxtArenas<'tcx>, - def_map: DefMap, + def_map: RefCell, named_region_map: resolve_lifetime::NamedRegionMap, map: ast_map::Map<'tcx>, freevars: FreevarMap, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 4f602abfbb586..e9a0efe76cb42 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -1150,7 +1150,7 @@ pub struct Resolver<'a, 'tcx:'a> { // The idents for the primitive types. primitive_type_table: PrimitiveTypeTable, - def_map: DefMap, + def_map: RefCell, freevars: FreevarMap, freevars_seen: NodeMap>, export_map: ExportMap, @@ -4026,7 +4026,7 @@ fn module_to_string(module: &Module) -> String { pub struct CrateMap { - pub def_map: DefMap, + pub def_map: RefCell, pub freevars: FreevarMap, pub export_map: ExportMap, pub trait_map: TraitMap, diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 3c53d55886565..6678d1c34a0c4 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -222,6 +222,7 @@ use util::nodemap::FnvHashMap; use util::ppaux; use std; +use std::cell::RefCell; use std::cmp::Ordering; use std::fmt; use std::rc::Rc; @@ -495,7 +496,7 @@ fn expand_nested_bindings<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, } fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, - dm: &DefMap, + dm: &RefCell, m: &[Match<'a, 'p, 'blk, 'tcx>], col: usize, val: MatchInput, @@ -541,7 +542,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, } fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, - dm: &DefMap, + dm: &RefCell, m: &[Match<'a, 'p, 'blk, 'tcx>], col: usize, val: MatchInput) @@ -596,7 +597,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, fn enter_opt<'a, 'p, 'blk, 'tcx>( bcx: Block<'blk, 'tcx>, _: ast::NodeId, - dm: &DefMap, + dm: &RefCell, m: &[Match<'a, 'p, 'blk, 'tcx>], opt: &Opt, col: usize, @@ -842,8 +843,8 @@ impl FailureHandler { } } -fn pick_column_to_specialize(def_map: &DefMap, m: &[Match]) -> Option { - fn pat_score(def_map: &DefMap, pat: &hir::Pat) -> usize { +fn pick_column_to_specialize(def_map: &RefCell, m: &[Match]) -> Option { + fn pat_score(def_map: &RefCell, pat: &hir::Pat) -> usize { match pat.node { hir::PatIdent(_, _, Some(ref inner)) => pat_score(def_map, &**inner), _ if pat_is_refutable(def_map, pat) => 1, From f5781f143c1dfb2913e2402d880ea136ad8da43a Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Wed, 4 Nov 2015 00:20:31 -0600 Subject: [PATCH 51/53] Remove use of RefCell in check_static_recursion --- src/librustc/middle/check_static_recursion.rs | 8 ++++---- src/librustc_driver/driver.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/librustc/middle/check_static_recursion.rs b/src/librustc/middle/check_static_recursion.rs index cfd7d3548e065..dd49010c43672 100644 --- a/src/librustc/middle/check_static_recursion.rs +++ b/src/librustc/middle/check_static_recursion.rs @@ -27,7 +27,7 @@ use std::cell::RefCell; struct CheckCrateVisitor<'a, 'ast: 'a> { sess: &'a Session, - def_map: &'a RefCell, + def_map: &'a DefMap, ast_map: &'a ast_map::Map<'ast>, // `discriminant_map` is a cache that associates the `NodeId`s of local // variant definitions with the discriminant expression that applies to @@ -92,7 +92,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckCrateVisitor<'a, 'ast> { pub fn check_crate<'ast>(sess: &Session, krate: &'ast hir::Crate, - def_map: &RefCell, + def_map: &DefMap, ast_map: &ast_map::Map<'ast>) { let mut visitor = CheckCrateVisitor { sess: sess, @@ -108,7 +108,7 @@ struct CheckItemRecursionVisitor<'a, 'ast: 'a> { root_span: &'a Span, sess: &'a Session, ast_map: &'a ast_map::Map<'ast>, - def_map: &'a RefCell, + def_map: &'a DefMap, discriminant_map: &'a RefCell>>, idstack: Vec, } @@ -237,7 +237,7 @@ impl<'a, 'ast: 'a> Visitor<'ast> for CheckItemRecursionVisitor<'a, 'ast> { fn visit_expr(&mut self, e: &'ast hir::Expr) { match e.node { hir::ExprPath(..) => { - match self.def_map.borrow().get(&e.id).map(|d| d.base_def) { + match self.def_map.get(&e.id).map(|d| d.base_def) { Some(DefStatic(def_id, _)) | Some(DefAssociatedConst(def_id)) | Some(DefConst(def_id)) => { diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 06708a5127f34..558ecf85511c8 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -718,7 +718,7 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, middle::check_loop::check_crate(sess, krate)); time(time_passes, "static item recursion checking", || - middle::check_static_recursion::check_crate(sess, krate, &def_map, &ast_map)); + middle::check_static_recursion::check_crate(sess, krate, &def_map.borrow(), &ast_map)); ty::ctxt::create_and_enter(sess, arenas, From 1ca1874986206b0d635b69e91f33195624bae74f Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Wed, 4 Nov 2015 00:26:41 -0600 Subject: [PATCH 52/53] Remove use of RefCell in resolve_lifetime --- src/librustc/middle/resolve_lifetime.rs | 7 +++---- src/librustc_driver/driver.rs | 4 ++-- src/librustc_driver/test.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/librustc/middle/resolve_lifetime.rs b/src/librustc/middle/resolve_lifetime.rs index 5035ac12a85f7..fa0c6c41ce5cc 100644 --- a/src/librustc/middle/resolve_lifetime.rs +++ b/src/librustc/middle/resolve_lifetime.rs @@ -23,7 +23,6 @@ use middle::def::{self, DefMap}; use middle::region; use middle::subst; use middle::ty; -use std::cell::RefCell; use std::fmt; use std::mem::replace; use syntax::ast; @@ -55,7 +54,7 @@ struct LifetimeContext<'a> { sess: &'a Session, named_region_map: &'a mut NamedRegionMap, scope: Scope<'a>, - def_map: &'a RefCell, + def_map: &'a DefMap, // Deep breath. Our representation for poly trait refs contains a single // binder and thus we only allow a single level of quantification. However, // the syntax of Rust permits quantification in two places, e.g., `T: for <'a> Foo<'a>` @@ -94,7 +93,7 @@ type Scope<'a> = &'a ScopeChain<'a>; static ROOT_SCOPE: ScopeChain<'static> = RootScope; -pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &RefCell) -> NamedRegionMap { +pub fn krate(sess: &Session, krate: &hir::Crate, def_map: &DefMap) -> NamedRegionMap { let mut named_region_map = NodeMap(); visit::walk_crate(&mut LifetimeContext { sess: sess, @@ -206,7 +205,7 @@ impl<'a, 'v> Visitor<'v> for LifetimeContext<'a> { hir::TyPath(None, ref path) => { // if this path references a trait, then this will resolve to // a trait ref, which introduces a binding scope. - match self.def_map.borrow().get(&ty.id).map(|d| (d.base_def, d.depth)) { + match self.def_map.get(&ty.id).map(|d| (d.base_def, d.depth)) { Some((def::DefTrait(..), 0)) => { self.with(LateScope(&Vec::new(), self.scope), |_, this| { this.visit_path(path, ty.id); diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 558ecf85511c8..2237e19c8e7da 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -700,8 +700,8 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: &'tcx Session, syntax::ext::mtwt::clear_tables(); } - let named_region_map = time(time_passes, "lifetime resolution", - || middle::resolve_lifetime::krate(sess, krate, &def_map)); + let named_region_map = time(time_passes, "lifetime resolution", || + middle::resolve_lifetime::krate(sess, krate, &def_map.borrow())); time(time_passes, "looking for entry point", || middle::entry::find_entry_point(sess, &ast_map)); diff --git a/src/librustc_driver/test.rs b/src/librustc_driver/test.rs index 4bbc22ef1a273..5cd6bfa879033 100644 --- a/src/librustc_driver/test.rs +++ b/src/librustc_driver/test.rs @@ -134,7 +134,7 @@ fn test_env(source_string: &str, let lang_items = lang_items::collect_language_items(&sess, &ast_map); let resolve::CrateMap { def_map, freevars, .. } = resolve::resolve_crate(&sess, &ast_map, resolve::MakeGlobMap::No); - let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map); + let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map.borrow()); let region_map = region::resolve_crate(&sess, krate); ty::ctxt::create_and_enter(&sess, &arenas, From b1788ef8e1b9e2142dbb20d1f5a325fc9b9cb592 Mon Sep 17 00:00:00 2001 From: Jonathan S Date: Wed, 4 Nov 2015 06:26:00 -0600 Subject: [PATCH 53/53] Remove use of RefCell in the simpler parts of pat_util --- src/librustc/middle/cfg/construct.rs | 2 +- src/librustc/middle/check_match.rs | 8 ++--- src/librustc/middle/dead.rs | 4 +-- src/librustc/middle/expr_use_visitor.rs | 4 +-- src/librustc/middle/pat_util.rs | 32 +++++++++---------- src/librustc_mir/hair/cx/pattern.rs | 4 +-- src/librustc_trans/trans/_match.rs | 8 ++--- .../trans/debuginfo/create_scope_map.rs | 2 +- src/librustc_typeck/check/_match.rs | 7 ++-- src/librustc_typeck/check/mod.rs | 2 +- src/librustc_typeck/check/writeback.rs | 2 +- 11 files changed, 38 insertions(+), 37 deletions(-) diff --git a/src/librustc/middle/cfg/construct.rs b/src/librustc/middle/cfg/construct.rs index 9f83cb9fddea4..5b931857decca 100644 --- a/src/librustc/middle/cfg/construct.rs +++ b/src/librustc/middle/cfg/construct.rs @@ -472,7 +472,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> { let guard_exit = self.expr(&**guard, guard_start); let this_has_bindings = pat_util::pat_contains_bindings_or_wild( - &self.tcx.def_map, &**pat); + &self.tcx.def_map.borrow(), &**pat); // If both this pattern and the previous pattern // were free of bindings, they must consist only diff --git a/src/librustc/middle/check_match.rs b/src/librustc/middle/check_match.rs index fce96457d174b..f46e55e244140 100644 --- a/src/librustc/middle/check_match.rs +++ b/src/librustc/middle/check_match.rs @@ -702,7 +702,7 @@ fn is_useful(cx: &MatchCheckCtxt, Some(constructor) => { let matrix = rows.iter().filter_map(|r| { - if pat_is_binding_or_wild(&cx.tcx.def_map, raw_pat(r[0])) { + if pat_is_binding_or_wild(&cx.tcx.def_map.borrow(), raw_pat(r[0])) { Some(r[1..].to_vec()) } else { None @@ -1073,7 +1073,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, // check legality of moving out of the enum // x @ Foo(..) is legal, but x @ Foo(y) isn't. - if sub.map_or(false, |p| pat_contains_bindings(def_map, &*p)) { + if sub.map_or(false, |p| pat_contains_bindings(&def_map.borrow(), &*p)) { span_err!(cx.tcx.sess, p.span, E0007, "cannot bind by-move with sub-bindings"); } else if has_guard { span_err!(cx.tcx.sess, p.span, E0008, "cannot bind by-move into a pattern guard"); @@ -1086,7 +1086,7 @@ fn check_legality_of_move_bindings(cx: &MatchCheckCtxt, for pat in pats { front_util::walk_pat(&**pat, |p| { - if pat_is_binding(def_map, &*p) { + if pat_is_binding(&def_map.borrow(), &*p) { match p.node { hir::PatIdent(hir::BindByValue(_), _, ref sub) => { let pat_ty = tcx.node_id_to_type(p.id); @@ -1181,7 +1181,7 @@ struct AtBindingPatternVisitor<'a, 'b:'a, 'tcx:'b> { impl<'a, 'b, 'tcx, 'v> Visitor<'v> for AtBindingPatternVisitor<'a, 'b, 'tcx> { fn visit_pat(&mut self, pat: &Pat) { - if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map, pat) { + if !self.bindings_allowed && pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) { span_err!(self.cx.tcx.sess, pat.span, E0303, "pattern bindings are not allowed \ after an `@`"); diff --git a/src/librustc/middle/dead.rs b/src/librustc/middle/dead.rs index 1a1a9d4b1b48f..b4280f86c7d58 100644 --- a/src/librustc/middle/dead.rs +++ b/src/librustc/middle/dead.rs @@ -250,7 +250,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { fn visit_arm(&mut self, arm: &hir::Arm) { if arm.pats.len() == 1 { let pat = &*arm.pats[0]; - let variants = pat_util::necessary_variants(&self.tcx.def_map, pat); + let variants = pat_util::necessary_variants(&self.tcx.def_map.borrow(), pat); // Inside the body, ignore constructions of variants // necessary for the pattern to match. Those construction sites @@ -270,7 +270,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for MarkSymbolVisitor<'a, 'tcx> { hir::PatStruct(_, ref fields, _) => { self.handle_field_pattern_match(pat, fields); } - _ if pat_util::pat_is_const(def_map, pat) => { + _ if pat_util::pat_is_const(&def_map.borrow(), pat) => { // it might be the only use of a const self.lookup_and_handle_definition(&pat.id) } diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs index 6e469da33f98e..ce8d74bf191c7 100644 --- a/src/librustc/middle/expr_use_visitor.rs +++ b/src/librustc/middle/expr_use_visitor.rs @@ -934,7 +934,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { return_if_err!(self.mc.cat_pattern(cmt_discr, pat, |_mc, cmt_pat, pat| { let tcx = self.tcx(); let def_map = &self.tcx().def_map; - if pat_util::pat_is_binding(def_map, pat) { + if pat_util::pat_is_binding(&def_map.borrow(), pat) { match pat.node { hir::PatIdent(hir::BindByRef(_), _, _) => mode.lub(BorrowingMatch), @@ -969,7 +969,7 @@ impl<'d,'t,'a,'tcx> ExprUseVisitor<'d,'t,'a,'tcx> { let def_map = &self.tcx().def_map; let delegate = &mut self.delegate; return_if_err!(mc.cat_pattern(cmt_discr.clone(), pat, |mc, cmt_pat, pat| { - if pat_util::pat_is_binding(def_map, pat) { + if pat_util::pat_is_binding(&def_map.borrow(), pat) { let tcx = typer.tcx; debug!("binding cmt_pat={:?} pat={:?} match_mode={:?}", diff --git a/src/librustc/middle/pat_util.rs b/src/librustc/middle/pat_util.rs index 77ffd0b606ebe..09132396054ff 100644 --- a/src/librustc/middle/pat_util.rs +++ b/src/librustc/middle/pat_util.rs @@ -32,13 +32,13 @@ pub fn pat_id_map(dm: &RefCell, pat: &hir::Pat) -> PatIdMap { map } -pub fn pat_is_refutable(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_refutable(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatLit(_) | hir::PatRange(_, _) | hir::PatQPath(..) => true, hir::PatEnum(_, _) | hir::PatIdent(_, _, None) | hir::PatStruct(..) => { - match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + match dm.get(&pat.id).map(|d| d.full_def()) { Some(DefVariant(..)) => true, _ => false } @@ -48,12 +48,12 @@ pub fn pat_is_refutable(dm: &RefCell, pat: &hir::Pat) -> bool { } } -pub fn pat_is_variant_or_struct(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_variant_or_struct(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatEnum(_, _) | hir::PatIdent(_, _, None) | hir::PatStruct(..) => { - match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + match dm.get(&pat.id).map(|d| d.full_def()) { Some(DefVariant(..)) | Some(DefStruct(..)) => true, _ => false } @@ -62,10 +62,10 @@ pub fn pat_is_variant_or_struct(dm: &RefCell, pat: &hir::Pat) -> bool { } } -pub fn pat_is_const(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_const(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => { - match dm.borrow().get(&pat.id).map(|d| d.full_def()) { + match dm.get(&pat.id).map(|d| d.full_def()) { Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, _ => false } @@ -76,10 +76,10 @@ pub fn pat_is_const(dm: &RefCell, pat: &hir::Pat) -> bool { // Same as above, except that partially-resolved defs cause `false` to be // returned instead of a panic. -pub fn pat_is_resolved_const(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_resolved_const(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(_, _, None) | hir::PatEnum(..) | hir::PatQPath(..) => { - match dm.borrow().get(&pat.id) + match dm.get(&pat.id) .and_then(|d| if d.depth == 0 { Some(d.base_def) } else { None } ) { Some(DefConst(..)) | Some(DefAssociatedConst(..)) => true, @@ -90,7 +90,7 @@ pub fn pat_is_resolved_const(dm: &RefCell, pat: &hir::Pat) -> bool { } } -pub fn pat_is_binding(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_binding(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(..) => { !pat_is_variant_or_struct(dm, pat) && @@ -100,7 +100,7 @@ pub fn pat_is_binding(dm: &RefCell, pat: &hir::Pat) -> bool { } } -pub fn pat_is_binding_or_wild(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_is_binding_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { match pat.node { hir::PatIdent(..) => pat_is_binding(dm, pat), hir::PatWild => true, @@ -115,7 +115,7 @@ pub fn pat_bindings(dm: &RefCell, pat: &hir::Pat, mut it: I) where { walk_pat(pat, |p| { match p.node { - hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => { + hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { it(binding_mode, p.id, p.span, &respan(pth.span, pth.node.name)); } _ => {} @@ -129,7 +129,7 @@ pub fn pat_bindings_hygienic(dm: &RefCell, pat: &hir::Pat, mut it: I) { walk_pat(pat, |p| { match p.node { - hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(dm, p) => { + hir::PatIdent(binding_mode, ref pth, _) if pat_is_binding(&dm.borrow(), p) => { it(binding_mode, p.id, p.span, &respan(pth.span, pth.node)); } _ => {} @@ -140,7 +140,7 @@ pub fn pat_bindings_hygienic(dm: &RefCell, pat: &hir::Pat, mut it: I) /// Checks if the pattern contains any patterns that bind something to /// an ident, e.g. `foo`, or `Foo(foo)` or `foo @ Bar(..)`. -pub fn pat_contains_bindings(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_contains_bindings(dm: &DefMap, pat: &hir::Pat) -> bool { let mut contains_bindings = false; walk_pat(pat, |p| { if pat_is_binding(dm, p) { @@ -185,7 +185,7 @@ pub fn arm_contains_ref_binding(dm: &RefCell, arm: &hir::Arm) -> Option< /// Checks if the pattern contains any patterns that bind something to /// an ident or wildcard, e.g. `foo`, or `Foo(_)`, `foo @ Bar(..)`, -pub fn pat_contains_bindings_or_wild(dm: &RefCell, pat: &hir::Pat) -> bool { +pub fn pat_contains_bindings_or_wild(dm: &DefMap, pat: &hir::Pat) -> bool { let mut contains_bindings = false; walk_pat(pat, |p| { if pat_is_binding_or_wild(dm, p) { @@ -221,14 +221,14 @@ pub fn def_to_path(tcx: &ty::ctxt, id: DefId) -> hir::Path { } /// Return variants that are necessary to exist for the pattern to match. -pub fn necessary_variants(dm: &RefCell, pat: &hir::Pat) -> Vec { +pub fn necessary_variants(dm: &DefMap, pat: &hir::Pat) -> Vec { let mut variants = vec![]; walk_pat(pat, |p| { match p.node { hir::PatEnum(_, _) | hir::PatIdent(_, _, None) | hir::PatStruct(..) => { - match dm.borrow().get(&p.id) { + match dm.get(&p.id) { Some(&PathResolution { base_def: DefVariant(_, id, _), .. }) => { variants.push(id); } diff --git a/src/librustc_mir/hair/cx/pattern.rs b/src/librustc_mir/hair/cx/pattern.rs index 31dbffa0ae348..fa96780417905 100644 --- a/src/librustc_mir/hair/cx/pattern.rs +++ b/src/librustc_mir/hair/cx/pattern.rs @@ -155,7 +155,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { }, hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..) - if pat_is_resolved_const(&cx.tcx.def_map, self.pat) => + if pat_is_resolved_const(&cx.tcx.def_map.borrow(), self.pat) => { let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def(); match def { @@ -231,7 +231,7 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> { } hir::PatIdent(bm, ref ident, ref sub) - if pat_is_binding(&cx.tcx.def_map, self.pat) => + if pat_is_binding(&cx.tcx.def_map.borrow(), self.pat) => { let id = match self.binding_map { None => self.pat.id, diff --git a/src/librustc_trans/trans/_match.rs b/src/librustc_trans/trans/_match.rs index 6678d1c34a0c4..0fb0407d3ba72 100644 --- a/src/librustc_trans/trans/_match.rs +++ b/src/librustc_trans/trans/_match.rs @@ -517,7 +517,7 @@ fn enter_match<'a, 'b, 'p, 'blk, 'tcx, F>(bcx: Block<'blk, 'tcx>, let mut bound_ptrs = br.bound_ptrs.clone(); match this.node { hir::PatIdent(_, ref path, None) => { - if pat_is_binding(dm, &*this) { + if pat_is_binding(&dm.borrow(), &*this) { bound_ptrs.push((path.node.name, val.val)); } } @@ -556,7 +556,7 @@ fn enter_default<'a, 'p, 'blk, 'tcx>(bcx: Block<'blk, 'tcx>, // Collect all of the matches that can match against anything. enter_match(bcx, dm, m, col, val, |pats| { - if pat_is_binding_or_wild(dm, &*pats[col]) { + if pat_is_binding_or_wild(&dm.borrow(), &*pats[col]) { let mut r = pats[..col].to_vec(); r.push_all(&pats[col + 1..]); Some(r) @@ -847,7 +847,7 @@ fn pick_column_to_specialize(def_map: &RefCell, m: &[Match]) -> Option, pat: &hir::Pat) -> usize { match pat.node { hir::PatIdent(_, _, Some(ref inner)) => pat_score(def_map, &**inner), - _ if pat_is_refutable(def_map, pat) => 1, + _ if pat_is_refutable(&def_map.borrow(), pat) => 1, _ => 0 } } @@ -1801,7 +1801,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, let ccx = bcx.ccx(); match pat.node { hir::PatIdent(pat_binding_mode, ref path1, ref inner) => { - if pat_is_binding(&tcx.def_map, &*pat) { + if pat_is_binding(&tcx.def_map.borrow(), &*pat) { // Allocate the stack slot where the value of this // binding will live and place it into the appropriate // map. diff --git a/src/librustc_trans/trans/debuginfo/create_scope_map.rs b/src/librustc_trans/trans/debuginfo/create_scope_map.rs index 01f5a32b1a3d4..0c424de9e10b8 100644 --- a/src/librustc_trans/trans/debuginfo/create_scope_map.rs +++ b/src/librustc_trans/trans/debuginfo/create_scope_map.rs @@ -167,7 +167,7 @@ fn walk_pattern(cx: &CrateContext, // Check if this is a binding. If so we need to put it on the // scope stack and maybe introduce an artificial scope - if pat_util::pat_is_binding(def_map, &*pat) { + if pat_util::pat_is_binding(&def_map.borrow(), &*pat) { let name = path1.node.name; diff --git a/src/librustc_typeck/check/_match.rs b/src/librustc_typeck/check/_match.rs index 694bb0e15ac79..cd7012cd4ec6d 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/src/librustc_typeck/check/_match.rs @@ -133,7 +133,8 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // subtyping doesn't matter here, as the value is some kind of scalar demand::eqtype(fcx, pat.span, expected, lhs_ty); } - hir::PatEnum(..) | hir::PatIdent(..) if pat_is_resolved_const(&tcx.def_map, pat) => { + hir::PatEnum(..) | hir::PatIdent(..) + if pat_is_resolved_const(&tcx.def_map.borrow(), pat) => { let const_did = tcx.def_map.borrow().get(&pat.id).unwrap().def_id(); let const_scheme = tcx.lookup_item_type(const_did); assert!(const_scheme.generics.is_empty()); @@ -149,7 +150,7 @@ pub fn check_pat<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, // is good enough. demand::suptype(fcx, pat.span, expected, const_ty); } - hir::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map, pat) => { + hir::PatIdent(bm, ref path, ref sub) if pat_is_binding(&tcx.def_map.borrow(), pat) => { let typ = fcx.local_ty(pat.span, pat.id); match bm { hir::BindByRef(mutbl) => { @@ -410,7 +411,7 @@ pub fn check_dereferencable<'a, 'tcx>(pcx: &pat_ctxt<'a, 'tcx>, inner: &hir::Pat) -> bool { let fcx = pcx.fcx; let tcx = pcx.fcx.ccx.tcx; - if pat_is_binding(&tcx.def_map, inner) { + if pat_is_binding(&tcx.def_map.borrow(), inner) { let expected = fcx.infcx().shallow_resolve(expected); expected.builtin_deref(true, ty::NoPreference).map_or(true, |mt| match mt.ty.sty { ty::TyTrait(_) => { diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index dc2b2b75ab6d1..cfa32bc073a1f 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -529,7 +529,7 @@ impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { // Add pattern bindings. fn visit_pat(&mut self, p: &'tcx hir::Pat) { if let hir::PatIdent(_, ref path1, _) = p.node { - if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map, p) { + if pat_util::pat_is_binding(&self.fcx.ccx.tcx.def_map.borrow(), p) { let var_ty = self.assign(p.span, p.id, None); self.fcx.require_type_is_sized(var_ty, p.span, diff --git a/src/librustc_typeck/check/writeback.rs b/src/librustc_typeck/check/writeback.rs index cfab28f923e09..5b1fafe09fac9 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/src/librustc_typeck/check/writeback.rs @@ -57,7 +57,7 @@ pub fn resolve_type_vars_in_fn(fcx: &FnCtxt, wbcx.visit_pat(&*arg.pat); // Privacy needs the type for the whole pattern, not just each binding - if !pat_util::pat_is_binding(&fcx.tcx().def_map, &*arg.pat) { + if !pat_util::pat_is_binding(&fcx.tcx().def_map.borrow(), &*arg.pat) { wbcx.visit_node_id(ResolvingPattern(arg.pat.span), arg.pat.id); }