mirror of
https://git.proxmox.com/git/rustc
synced 2026-01-22 20:44:32 +00:00
Merge tag 'upstream-tar/1.4.0+dfsg1'
Upstream version 1.4.0+dfsg1
This commit is contained in:
commit
69c36f97de
@ -10,6 +10,7 @@ links to the major sections:
|
||||
* [Writing Documentation](#writing-documentation)
|
||||
* [Issue Triage](#issue-triage)
|
||||
* [Out-of-tree Contributions](#out-of-tree-contributions)
|
||||
* [Helpful Links and Information](#helpful-links-and-information)
|
||||
|
||||
If you have questions, please make a post on [internals.rust-lang.org][internals] or
|
||||
hop on [#rust-internals][pound-rust-internals].
|
||||
@ -17,8 +18,8 @@ hop on [#rust-internals][pound-rust-internals].
|
||||
As a reminder, all contributors are expected to follow our [Code of Conduct][coc].
|
||||
|
||||
[pound-rust-internals]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust-internals
|
||||
[internals]: http://internals.rust-lang.org
|
||||
[coc]: http://www.rust-lang.org/conduct.html
|
||||
[internals]: https://internals.rust-lang.org
|
||||
[coc]: https://www.rust-lang.org/conduct.html
|
||||
|
||||
## Feature Requests
|
||||
|
||||
@ -207,6 +208,31 @@ it to [Crates.io](http://crates.io). Easier said than done, but very, very
|
||||
valuable!
|
||||
|
||||
[pound-rust]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[users]: https://users.rust-lang.org/
|
||||
[so]: http://stackoverflow.com/questions/tagged/rust
|
||||
[community-library]: https://github.com/rust-lang/rfcs/labels/A-community-library
|
||||
|
||||
## Helpful Links and Information
|
||||
|
||||
For people new to Rust, and just starting to contribute, or even for
|
||||
more seasoned developers, some useful places to look for information
|
||||
are:
|
||||
|
||||
* The [Rust Internals forum][rif], a place to ask questions and
|
||||
discuss Rust's internals
|
||||
* The [generated documentation for rust's compiler][gdfrustc]
|
||||
* The [rust referance][rr], even though it doesn't specifically talk about Rust's internals, its a great reasource nontheless
|
||||
* Although out of date, [Tom Lee's great blog article][tlgba] is very helpful
|
||||
* [rustaceans.org][ro] is helpful, but mostly dedicated to IRC
|
||||
* The [Rust Compiler Testing Docs][rctd]
|
||||
* For @bors, [this cheetsheat][cheetsheat] is helpful (Remember to replace `@homu` with `@bors` in the commands that you use.)
|
||||
* **Google**!
|
||||
* Don't be afraid to ask! The Rust community is friendly and helpful.
|
||||
|
||||
[gdfrustc]: http://manishearth.github.io/rust-internals-docs/rustc/
|
||||
[rif]: http://internals.rust-lang.org
|
||||
[rr]: https://doc.rust-lang.org/book/README.html
|
||||
[tlgba]: http://tomlee.co/2014/04/03/a-more-detailed-tour-of-the-rust-compiler/
|
||||
[ro]: http://www.rustaceans.org/
|
||||
[rctd]: ./COMPILER_TESTS.md
|
||||
[cheetsheat]: http://buildbot.rust-lang.org/homu/
|
||||
|
||||
98
COPYRIGHT
98
COPYRIGHT
@ -22,104 +22,6 @@ The Rust Project includes packages written by third parties.
|
||||
The following third party packages are included, and carry
|
||||
their own copyright notices and license terms:
|
||||
|
||||
* Two header files that are part of the Valgrind
|
||||
package. These files are found at src/rt/valgrind/valgrind.h and
|
||||
src/rt/valgrind/memcheck.h, within this distribution. These files
|
||||
are redistributed under the following terms, as noted in
|
||||
them:
|
||||
|
||||
for src/rt/valgrind/valgrind.h:
|
||||
|
||||
This file is part of Valgrind, a dynamic binary
|
||||
instrumentation framework.
|
||||
|
||||
Copyright (C) 2000-2010 Julian Seward. All rights
|
||||
reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with
|
||||
or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
2. The origin of this software must not be
|
||||
misrepresented; you must not claim that you wrote the
|
||||
original software. If you use this software in a
|
||||
product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not
|
||||
required.
|
||||
|
||||
3. Altered source versions must be plainly marked as
|
||||
such, and must not be misrepresented as being the
|
||||
original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or
|
||||
promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
for src/rt/valgrind/memcheck.h:
|
||||
|
||||
This file is part of MemCheck, a heavyweight Valgrind
|
||||
tool for detecting memory errors.
|
||||
|
||||
Copyright (C) 2000-2010 Julian Seward. All rights
|
||||
reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with
|
||||
or without modification, are permitted provided that the
|
||||
following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above
|
||||
copyright notice, this list of conditions and the
|
||||
following disclaimer.
|
||||
|
||||
2. The origin of this software must not be
|
||||
misrepresented; you must not claim that you wrote the
|
||||
original software. If you use this software in a
|
||||
product, an acknowledgment in the product
|
||||
documentation would be appreciated but is not
|
||||
required.
|
||||
|
||||
3. Altered source versions must be plainly marked as
|
||||
such, and must not be misrepresented as being the
|
||||
original software.
|
||||
|
||||
4. The name of the author may not be used to endorse or
|
||||
promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
||||
NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
|
||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
|
||||
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
||||
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
||||
OF SUCH DAMAGE.
|
||||
|
||||
* The src/rt/miniz.c file, carrying an implementation of
|
||||
RFC1950/RFC1951 DEFLATE, by Rich Geldreich
|
||||
<richgel99@gmail.com>. All uses of this file are
|
||||
|
||||
31
README.md
31
README.md
@ -13,8 +13,8 @@ as standard libraries, tools and documentation for Rust.
|
||||
|
||||
Read ["Installing Rust"] from [The Book].
|
||||
|
||||
["Installing Rust"]: http://doc.rust-lang.org/book/installing-rust.html
|
||||
[The Book]: http://doc.rust-lang.org/book/index.html
|
||||
["Installing Rust"]: https://doc.rust-lang.org/book/installing-rust.html
|
||||
[The Book]: https://doc.rust-lang.org/book/index.html
|
||||
|
||||
## Building from Source
|
||||
|
||||
@ -65,6 +65,9 @@ Read ["Installing Rust"] from [The Book].
|
||||
tools.
|
||||
|
||||
```sh
|
||||
# Update package mirrors (may be needed if you have a fresh install of MSYS2)
|
||||
$ pacman -Sy pacman-mirrors
|
||||
|
||||
# Choose one based on platform:
|
||||
$ pacman -S mingw-w64-i686-toolchain
|
||||
$ pacman -S mingw-w64-x86_64-toolchain
|
||||
@ -82,6 +85,28 @@ Read ["Installing Rust"] from [The Book].
|
||||
$ make && make install
|
||||
```
|
||||
|
||||
## Building Documentation
|
||||
|
||||
If you’d like to build the documentation, it’s almost the same:
|
||||
|
||||
```sh
|
||||
./configure
|
||||
$ make docs
|
||||
```
|
||||
|
||||
Building the documentation requires building the compiler, so the above
|
||||
details will apply. Once you have the compiler built, you can
|
||||
|
||||
```sh
|
||||
$ make docs NO_REBUILD=1
|
||||
```
|
||||
|
||||
To make sure you don’t re-build the compiler because you made a change
|
||||
to some documentation.
|
||||
|
||||
The generated documentation will appear in a top-level `doc` directory,
|
||||
created by the `make` rule.
|
||||
|
||||
## Notes
|
||||
|
||||
Since the Rust compiler is written in Rust, it must be built by a
|
||||
@ -117,7 +142,7 @@ The Rust community congregates in a few places:
|
||||
|
||||
[Stack Overflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
[/r/rust]: http://reddit.com/r/rust
|
||||
[users.rust-lang.org]: http://users.rust-lang.org/
|
||||
[users.rust-lang.org]: https://users.rust-lang.org/
|
||||
|
||||
## Contributing
|
||||
|
||||
|
||||
291
RELEASES.md
291
RELEASES.md
@ -1,4 +1,173 @@
|
||||
Version 1.3.0 (September 2015)
|
||||
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]: `<Box<str>>::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<String>` and `FromIterator<String` are both implemented for
|
||||
`String`][es].
|
||||
* [`IntoIterator` is implemented for `Option<&T>` 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)
|
||||
==============================
|
||||
|
||||
* ~900 changes, numerous bugfixes
|
||||
@ -142,7 +311,7 @@ Misc
|
||||
[`Error`]: http://doc.rust-lang.org/nightly/std/error/trait.Error.html
|
||||
[`File`]: http://doc.rust-lang.org/nightly/std/fs/struct.File.html
|
||||
[`Hash`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html
|
||||
[`Hasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hash.html
|
||||
[`Hasher`]: http://doc.rust-lang.org/nightly/std/hash/trait.Hasher.html
|
||||
[`Send`]: http://doc.rust-lang.org/nightly/std/marker/trait.Send.html
|
||||
[`SliceConcatExt`]: http://doc.rust-lang.org/nightly/std/slice/trait.SliceConcatExt.html
|
||||
[`Stdin`]: http://doc.rust-lang.org/nightly/std/io/struct.Stdin.html
|
||||
@ -204,8 +373,8 @@ Misc
|
||||
[win4]: https://github.com/rust-lang/rust/pull/27210
|
||||
[xp]: https://github.com/rust-lang/rust/pull/26569
|
||||
|
||||
Version 1.2.0 (August 2015)
|
||||
===========================
|
||||
Version 1.2.0 (2015-08-07)
|
||||
==========================
|
||||
|
||||
* ~1200 changes, numerous bugfixes
|
||||
|
||||
@ -308,51 +477,51 @@ Misc
|
||||
* Fat pointers are now [passed in pairs of immediate arguments][fat],
|
||||
resulting in faster compile times and smaller code.
|
||||
|
||||
[`Extend`]: http://doc.rust-lang.org/nightly/std/iter/trait.Extend.html
|
||||
[`Extend`]: https://doc.rust-lang.org/nightly/std/iter/trait.Extend.html
|
||||
[extend-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0839-embrace-extend-extinguish.md
|
||||
[`iter::once`]: http://doc.rust-lang.org/nightly/std/iter/fn.once.html
|
||||
[`iter::empty`]: http://doc.rust-lang.org/nightly/std/iter/fn.empty.html
|
||||
[`matches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.matches
|
||||
[`rmatches`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatches
|
||||
[`Cell`]: http://doc.rust-lang.org/nightly/std/cell/struct.Cell.html
|
||||
[`RefCell`]: http://doc.rust-lang.org/nightly/std/cell/struct.RefCell.html
|
||||
[`wrapping_add`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_add
|
||||
[`wrapping_sub`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_sub
|
||||
[`wrapping_mul`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_mul
|
||||
[`wrapping_div`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_div
|
||||
[`wrapping_rem`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_rem
|
||||
[`wrapping_neg`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_neg
|
||||
[`wrapping_shl`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shl
|
||||
[`wrapping_shr`]: http://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shr
|
||||
[`Wrapping`]: http://doc.rust-lang.org/nightly/std/num/struct.Wrapping.html
|
||||
[`fmt::Formatter`]: http://doc.rust-lang.org/nightly/std/fmt/struct.Formatter.html
|
||||
[`fmt::Write`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Write.html
|
||||
[`io::Write`]: http://doc.rust-lang.org/nightly/std/io/trait.Write.html
|
||||
[`debug_struct`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_struct
|
||||
[`debug_tuple`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_tuple
|
||||
[`debug_list`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_list
|
||||
[`debug_set`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_set
|
||||
[`debug_map`]: http://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_map
|
||||
[`Debug`]: http://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
|
||||
[strup]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_uppercase
|
||||
[strlow]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase
|
||||
[`to_uppercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_uppercase
|
||||
[`to_lowercase`]: http://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_lowercase
|
||||
[`PoisonError`]: http://doc.rust-lang.org/nightly/std/sync/struct.PoisonError.html
|
||||
[`RwLock`]: http://doc.rust-lang.org/nightly/std/sync/struct.RwLock.html
|
||||
[`Mutex`]: http://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html
|
||||
[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`Stdio`]: http://doc.rust-lang.org/nightly/std/process/struct.Stdio.html
|
||||
[`ChildStdin`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdin.html
|
||||
[`ChildStdout`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStdout.html
|
||||
[`ChildStderr`]: http://doc.rust-lang.org/nightly/std/process/struct.ChildStderr.html
|
||||
[`io::ErrorKind`]: http://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html
|
||||
[`iter::once`]: https://doc.rust-lang.org/nightly/std/iter/fn.once.html
|
||||
[`iter::empty`]: https://doc.rust-lang.org/nightly/std/iter/fn.empty.html
|
||||
[`matches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.matches
|
||||
[`rmatches`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.rmatches
|
||||
[`Cell`]: https://doc.rust-lang.org/nightly/std/cell/struct.Cell.html
|
||||
[`RefCell`]: https://doc.rust-lang.org/nightly/std/cell/struct.RefCell.html
|
||||
[`wrapping_add`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_add
|
||||
[`wrapping_sub`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_sub
|
||||
[`wrapping_mul`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_mul
|
||||
[`wrapping_div`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_div
|
||||
[`wrapping_rem`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_rem
|
||||
[`wrapping_neg`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_neg
|
||||
[`wrapping_shl`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shl
|
||||
[`wrapping_shr`]: https://doc.rust-lang.org/nightly/std/primitive.i8.html#method.wrapping_shr
|
||||
[`Wrapping`]: https://doc.rust-lang.org/nightly/std/num/struct.Wrapping.html
|
||||
[`fmt::Formatter`]: https://doc.rust-lang.org/nightly/std/fmt/struct.Formatter.html
|
||||
[`fmt::Write`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Write.html
|
||||
[`io::Write`]: https://doc.rust-lang.org/nightly/std/io/trait.Write.html
|
||||
[`debug_struct`]: https://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_struct
|
||||
[`debug_tuple`]: https://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_tuple
|
||||
[`debug_list`]: https://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_list
|
||||
[`debug_set`]: https://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_set
|
||||
[`debug_map`]: https://doc.rust-lang.org/nightly/core/fmt/struct.Formatter.html#method.debug_map
|
||||
[`Debug`]: https://doc.rust-lang.org/nightly/std/fmt/trait.Debug.html
|
||||
[strup]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_uppercase
|
||||
[strlow]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.to_lowercase
|
||||
[`to_uppercase`]: https://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_uppercase
|
||||
[`to_lowercase`]: https://doc.rust-lang.org/nightly/std/primitive.char.html#method.to_lowercase
|
||||
[`PoisonError`]: https://doc.rust-lang.org/nightly/std/sync/struct.PoisonError.html
|
||||
[`RwLock`]: https://doc.rust-lang.org/nightly/std/sync/struct.RwLock.html
|
||||
[`Mutex`]: https://doc.rust-lang.org/nightly/std/sync/struct.Mutex.html
|
||||
[`FromRawFd`]: https://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: https://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`Stdio`]: https://doc.rust-lang.org/nightly/std/process/struct.Stdio.html
|
||||
[`ChildStdin`]: https://doc.rust-lang.org/nightly/std/process/struct.ChildStdin.html
|
||||
[`ChildStdout`]: https://doc.rust-lang.org/nightly/std/process/struct.ChildStdout.html
|
||||
[`ChildStderr`]: https://doc.rust-lang.org/nightly/std/process/struct.ChildStderr.html
|
||||
[`io::ErrorKind`]: https://doc.rust-lang.org/nightly/std/io/enum.ErrorKind.html
|
||||
[debugfmt]: https://www.reddit.com/r/rust/comments/3ceaui/psa_produces_prettyprinted_debug_output/
|
||||
[`DerefMut`]: http://doc.rust-lang.org/nightly/std/ops/trait.DerefMut.html
|
||||
[`mem::align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.align_of.html
|
||||
[`DerefMut`]: https://doc.rust-lang.org/nightly/std/ops/trait.DerefMut.html
|
||||
[`mem::align_of`]: https://doc.rust-lang.org/nightly/std/mem/fn.align_of.html
|
||||
[align]: https://github.com/rust-lang/rust/pull/25646
|
||||
[`mem::min_align_of`]: http://doc.rust-lang.org/nightly/std/mem/fn.min_align_of.html
|
||||
[`mem::min_align_of`]: https://doc.rust-lang.org/nightly/std/mem/fn.min_align_of.html
|
||||
[typos]: https://github.com/rust-lang/rust/pull/26087
|
||||
[nop]: https://github.com/rust-lang/rust/pull/26336
|
||||
[fat]: https://github.com/rust-lang/rust/pull/26411
|
||||
@ -362,7 +531,7 @@ Misc
|
||||
[ad]: https://github.com/rust-lang/rust/pull/27382
|
||||
[win]: https://github.com/rust-lang/rust/pull/25350
|
||||
|
||||
Version 1.1.0 (June 2015)
|
||||
Version 1.1.0 (2015-06-25)
|
||||
=========================
|
||||
|
||||
* ~850 changes, numerous bugfixes
|
||||
@ -443,14 +612,14 @@ Misc
|
||||
* [The `drop_with_repr_extern` lint warns about mixing `repr(C)`
|
||||
with `Drop`][drop].
|
||||
|
||||
[`str::split_whitespace`]: http://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
|
||||
[`FromRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: http://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`std::os::unix::symlink`]: http://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html
|
||||
[`IntoIterator`]: http://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html
|
||||
[`From`]: http://doc.rust-lang.org/nightly/std/convert/trait.From.html
|
||||
[`str::split_whitespace`]: https://doc.rust-lang.org/nightly/std/primitive.str.html#method.split_whitespace
|
||||
[`FromRawFd`]: https://doc.rust-lang.org/nightly/std/os/unix/io/trait.FromRawFd.html
|
||||
[`AsRawFd`]: https://doc.rust-lang.org/nightly/std/os/unix/io/trait.AsRawFd.html
|
||||
[`std::os::unix::symlink`]: https://doc.rust-lang.org/nightly/std/os/unix/fs/fn.symlink.html
|
||||
[`IntoIterator`]: https://doc.rust-lang.org/nightly/std/iter/trait.IntoIterator.html
|
||||
[`From`]: https://doc.rust-lang.org/nightly/std/convert/trait.From.html
|
||||
[rf]: https://github.com/rust-lang/rust/pull/24491
|
||||
[err-index]: http://doc.rust-lang.org/error-index.html
|
||||
[err-index]: https://doc.rust-lang.org/error-index.html
|
||||
[sk]: https://github.com/rust-lang/rust/pull/24615
|
||||
[pre]: https://github.com/rust-lang/rust/pull/25323
|
||||
[file]: https://github.com/rust-lang/rust/pull/24598
|
||||
@ -464,16 +633,16 @@ Misc
|
||||
[pie]: https://github.com/rust-lang/rust/pull/24953
|
||||
[abs]: https://github.com/rust-lang/rust/pull/25441
|
||||
[c]: https://github.com/rust-lang/rust/pull/25496
|
||||
[`Cloned`]: http://doc.rust-lang.org/nightly/std/iter/struct.Cloned.html
|
||||
[`Incoming`]: http://doc.rust-lang.org/nightly/std/net/struct.Incoming.html
|
||||
[`Cloned`]: https://doc.rust-lang.org/nightly/std/iter/struct.Cloned.html
|
||||
[`Incoming`]: https://doc.rust-lang.org/nightly/std/net/struct.Incoming.html
|
||||
[inc]: https://github.com/rust-lang/rust/pull/25522
|
||||
[bh]: https://github.com/rust-lang/rust/pull/25856
|
||||
[`BinaryHeap`]: http://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html
|
||||
[`BinaryHeap`]: https://doc.rust-lang.org/nightly/std/collections/struct.BinaryHeap.html
|
||||
[ll]: https://github.com/rust-lang/rust/pull/26022
|
||||
[`split_off`]: http://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html#method.split_off
|
||||
[`split_off`]: https://doc.rust-lang.org/nightly/collections/linked_list/struct.LinkedList.html#method.split_off
|
||||
[drop]: https://github.com/rust-lang/rust/pull/24935
|
||||
|
||||
Version 1.0.0 (May 2015)
|
||||
Version 1.0.0 (2015-05-15)
|
||||
========================
|
||||
|
||||
* ~1500 changes, numerous bugfixes
|
||||
@ -714,7 +883,7 @@ Version 1.0.0-alpha.2 (February 2015)
|
||||
[drop]: https://github.com/rust-lang/rust/pull/21972
|
||||
[drop-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md
|
||||
[feat]: https://github.com/rust-lang/rust/pull/21248
|
||||
[feat-forum]: http://users.rust-lang.org/t/psa-important-info-about-rustcs-new-feature-staging/82/5
|
||||
[feat-forum]: https://users.rust-lang.org/t/psa-important-info-about-rustcs-new-feature-staging/82/5
|
||||
[feat-rfc]: https://github.com/rust-lang/rfcs/blob/master/text/0507-release-channels.md
|
||||
[fmt]: https://github.com/rust-lang/rust/pull/21457
|
||||
[into]: https://github.com/rust-lang/rust/pull/20790
|
||||
@ -915,7 +1084,7 @@ Version 1.0.0-alpha (January 2015)
|
||||
[objsafe]: https://github.com/rust-lang/rfcs/blob/master/text/0255-object-safety.md
|
||||
[assoc]: https://github.com/rust-lang/rfcs/blob/master/text/0195-associated-items.md
|
||||
[ints]: https://github.com/rust-lang/rfcs/pull/544#issuecomment-68760871
|
||||
[trpl]: http://doc.rust-lang.org/book/index.html
|
||||
[trpl]: https://doc.rust-lang.org/book/index.html
|
||||
[rbe]: http://rustbyexample.com/
|
||||
|
||||
|
||||
|
||||
82
configure
vendored
82
configure
vendored
@ -602,11 +602,16 @@ valopt python "" "set path to python"
|
||||
valopt jemalloc-root "" "set directory where libjemalloc_pic.a is located"
|
||||
valopt build "${DEFAULT_BUILD}" "GNUs ./configure syntax LLVM build triple"
|
||||
valopt android-cross-path "/opt/ndk_standalone" "Android NDK standalone path (deprecated)"
|
||||
valopt i686-linux-android-ndk "" "i686-linux-android NDK standalone path"
|
||||
valopt arm-linux-androideabi-ndk "" "arm-linux-androideabi NDK standalone path"
|
||||
valopt aarch64-linux-android-ndk "" "aarch64-linux-android NDK standalone path"
|
||||
valopt release-channel "dev" "the name of the release channel to build"
|
||||
valopt musl-root "/usr/local" "MUSL root installation directory"
|
||||
|
||||
# Used on systems where "cc" and "ar" are unavailable
|
||||
valopt default-linker "cc" "the default linker"
|
||||
valopt default-ar "ar" "the default ar"
|
||||
|
||||
# Many of these are saved below during the "writing configuration" step
|
||||
# (others are conditionally saved).
|
||||
opt_nosave manage-submodules 1 "let the build manage the git submodules"
|
||||
@ -880,6 +885,28 @@ then
|
||||
CFG_DISABLE_JEMALLOC=1
|
||||
fi
|
||||
|
||||
# default gcc version under OpenBSD maybe too old, try using egcc, which is a
|
||||
# gcc version from ports
|
||||
if [ $CFG_OSTYPE = unknown-openbsd ]
|
||||
then
|
||||
if [ $("$CFG_GCC" --version 2>&1 | grep -c ' 4\.[0-6]') -ne 0 ]; then
|
||||
step_msg "older GCC found, try with egcc instead"
|
||||
|
||||
# probe again but using egcc
|
||||
probe CFG_GCC egcc
|
||||
|
||||
# and use egcc/eg++ for CC/CXX too if it was found
|
||||
# (but user setting has priority)
|
||||
if [ -n "$CFG_GCC" ]; then
|
||||
CC="${CC:-egcc}"
|
||||
CXX="${CXX:-eg++}"
|
||||
fi
|
||||
fi
|
||||
|
||||
step_msg "on OpenBSD, disabling jemalloc"
|
||||
CFG_DISABLE_JEMALLOC=1
|
||||
fi
|
||||
|
||||
# OS X 10.9, gcc is actually clang. This can cause some confusion in the build
|
||||
# system, so if we find that gcc is clang, we should just use clang directly.
|
||||
if [ $CFG_OSTYPE = apple-darwin -a -z "$CFG_ENABLE_CLANG" ]
|
||||
@ -951,7 +978,7 @@ then
|
||||
LLVM_VERSION=$($LLVM_CONFIG --version)
|
||||
|
||||
case $LLVM_VERSION in
|
||||
(3.[5-7]*)
|
||||
(3.[5-8]*)
|
||||
msg "found ok version of LLVM: $LLVM_VERSION"
|
||||
;;
|
||||
(*)
|
||||
@ -1025,7 +1052,7 @@ then
|
||||
esac
|
||||
else
|
||||
case $CFG_CLANG_VERSION in
|
||||
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7*)
|
||||
(3.2* | 3.3* | 3.4* | 3.5* | 3.6* | 3.7* | 3.8*)
|
||||
step_msg "found ok version of CLANG: $CFG_CLANG_VERSION"
|
||||
;;
|
||||
(*)
|
||||
@ -1164,27 +1191,56 @@ do
|
||||
#
|
||||
# Consequently here we try to detect when that happens and print an
|
||||
# error if it does.
|
||||
if $CFG_PYTHON -c 'import sys; print sys.argv[1]' `pwd` | grep '^/'
|
||||
if $CFG_PYTHON -c 'import sys; print sys.argv[1]' `pwd` | grep '^/' > /dev/null
|
||||
then
|
||||
err "python is silently translating windows paths to MSYS paths \
|
||||
and the build will fail if this python is used.\n\n \
|
||||
Either an official python install must be used or an \
|
||||
alternative python package in MinGW must be used."
|
||||
err "
|
||||
|
||||
python is silently translating windows paths to MSYS paths \
|
||||
and the build will fail if this python is used.
|
||||
|
||||
Either an official python install must be used or an \
|
||||
alternative python package in MinGW must be used.
|
||||
|
||||
If you are building under msys2 try installing the mingw-w64-x86_64-python2 \
|
||||
package instead of python2:
|
||||
|
||||
$ pacman -R python2 && pacman -S mingw-w64-x86_64-python2
|
||||
"
|
||||
fi
|
||||
|
||||
# MSVC requires cmake because that's how we're going to build LLVM
|
||||
probe_need CFG_CMAKE cmake
|
||||
|
||||
# There are three builds of cmake on windows: MSVC, MinGW and Cygwin
|
||||
# The Cygwin build does not have generators for Visual Studio, so
|
||||
# detect that here and error.
|
||||
if ! "$CFG_CMAKE" --help | sed -n '/^Generators/,$p' | grep 'Visual Studio' > /dev/null
|
||||
then
|
||||
err "
|
||||
|
||||
cmake does not support Visual Studio generators.
|
||||
|
||||
This is likely due to it being an msys/cygwin build of cmake, \
|
||||
rather than the required windows version, built using MinGW \
|
||||
or Visual Studio.
|
||||
|
||||
If you are building under msys2 try installing the mingw-w64-x86_64-cmake \
|
||||
package instead of cmake:
|
||||
|
||||
$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
|
||||
"
|
||||
fi
|
||||
|
||||
# Use the REG program to figure out where VS is installed
|
||||
# We need to figure out where cl.exe and link.exe are, so we do some
|
||||
# munging and some probing here. We also look for the default
|
||||
# INCLUDE and LIB variables for MSVC so we can set those in the
|
||||
# build system as well.
|
||||
install=$(reg QUERY \
|
||||
install=$(cmd //c reg QUERY \
|
||||
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0' \
|
||||
-v InstallDir)
|
||||
if [ -z "$install" ]; then
|
||||
install=$(reg QUERY \
|
||||
install=$(cmd //c reg QUERY \
|
||||
'HKLM\SOFTWARE\Wow6432Node\Microsoft\VisualStudio\12.0' \
|
||||
-v InstallDir)
|
||||
fi
|
||||
@ -1217,9 +1273,9 @@ do
|
||||
eval CFG_MSVC_LINK_$bits="\"$bindir/link.exe\""
|
||||
|
||||
vcvarsall="${CFG_MSVC_ROOT}/VC/vcvarsall.bat"
|
||||
include_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %INCLUDE%")
|
||||
include_path=$(cmd //V:ON //c "$vcvarsall" $msvc_part \& echo !INCLUDE!)
|
||||
need_ok "failed to learn about MSVC's INCLUDE"
|
||||
lib_path=$(cmd /c "\"$vcvarsall\" $msvc_part && cmd /c echo %LIB%")
|
||||
lib_path=$(cmd //V:ON //c "$vcvarsall" $msvc_part \& echo !LIB!)
|
||||
need_ok "failed to learn about MSVC's LIB"
|
||||
|
||||
eval CFG_MSVC_INCLUDE_PATH_${bits}="\"$include_path\""
|
||||
@ -1428,9 +1484,10 @@ do
|
||||
LLVM_BUILD_DIR=
|
||||
LLVM_INST_DIR=$CFG_LLVM_ROOT
|
||||
do_reconfigure=0
|
||||
# Check that LLVm FileCheck is available. Needed for the tests
|
||||
need_cmd $LLVM_INST_DIR/bin/FileCheck
|
||||
fi
|
||||
|
||||
|
||||
if [ ${do_reconfigure} -ne 0 ]
|
||||
then
|
||||
# because git is hilarious, it might have put the module index
|
||||
@ -1688,6 +1745,7 @@ putvar CFG_LIBDIR_RELATIVE
|
||||
putvar CFG_DISABLE_MANAGE_SUBMODULES
|
||||
putvar CFG_AARCH64_LINUX_ANDROID_NDK
|
||||
putvar CFG_ARM_LINUX_ANDROIDEABI_NDK
|
||||
putvar CFG_I686_LINUX_ANDROID_NDK
|
||||
putvar CFG_MANDIR
|
||||
|
||||
# Avoid spurious warnings from clang by feeding it original source on
|
||||
|
||||
@ -41,7 +41,7 @@ look for anything here (the default)
|
||||
.RE
|
||||
.TP
|
||||
\fB\-l\fR [\fIKIND\fR=]\fINAME\fR
|
||||
Link the generated crate(s) to the specified native library \fINAME\fR.
|
||||
Link the generated crate(s) to the specified library \fINAME\fR.
|
||||
The optional \fIKIND\fR can be one of \fIstatic\fR, \fIdylib\fR, or
|
||||
\fIframework\fR.
|
||||
If omitted, \fIdylib\fR is assumed.
|
||||
@ -113,7 +113,8 @@ Print version info and exit.
|
||||
Use verbose output.
|
||||
.TP
|
||||
\fB\-\-extern\fR \fINAME\fR=\fIPATH\fR
|
||||
Specify where an external rust library is located.
|
||||
Specify where an external rust library is located. These should match
|
||||
\fIextern\fR declarations in the crate's source code.
|
||||
.TP
|
||||
\fB\-\-sysroot\fR \fIPATH\fR
|
||||
Override the system root.
|
||||
|
||||
25
mk/cfg/i686-linux-android.mk
Normal file
25
mk/cfg/i686-linux-android.mk
Normal file
@ -0,0 +1,25 @@
|
||||
# i686-linux-android configuration
|
||||
CC_i686-linux-android=$(CFG_I686_LINUX_ANDROID_NDK)/bin/i686-linux-android-gcc
|
||||
CXX_i686-linux-android=$(CFG_I686_LINUX_ANDROID_NDK)/bin/i686-linux-android-g++
|
||||
CPP_i686-linux-android=$(CFG_I686_LINUX_ANDROID_NDK)/bin/i686-linux-android-gcc -E
|
||||
AR_i686-linux-android=$(CFG_I686_LINUX_ANDROID_NDK)/bin/i686-linux-android-ar
|
||||
CFG_LIB_NAME_i686-linux-android=lib$(1).so
|
||||
CFG_STATIC_LIB_NAME_i686-linux-android=lib$(1).a
|
||||
CFG_LIB_GLOB_i686-linux-android=lib$(1)-*.so
|
||||
CFG_LIB_DSYM_GLOB_i686-linux-android=lib$(1)-*.dylib.dSYM
|
||||
CFG_JEMALLOC_CFLAGS_i686-linux-android := -D__i686__ -DANDROID -D__ANDROID__ $(CFLAGS)
|
||||
CFG_GCCISH_CFLAGS_i686-linux-android := -Wall -g -fPIC -D__i686__ -DANDROID -D__ANDROID__ $(CFLAGS)
|
||||
CFG_GCCISH_CXXFLAGS_i686-linux-android := -fno-rtti $(CXXFLAGS)
|
||||
CFG_GCCISH_LINK_FLAGS_i686-linux-android := -shared -fPIC -ldl -g -lm -lsupc++
|
||||
CFG_GCCISH_DEF_FLAG_i686-linux-android := -Wl,--export-dynamic,--dynamic-list=
|
||||
CFG_LLC_FLAGS_i686-linux-android :=
|
||||
CFG_INSTALL_NAME_i686-linux-android =
|
||||
CFG_EXE_SUFFIX_i686-linux-android :=
|
||||
CFG_WINDOWSY_i686-linux-android :=
|
||||
CFG_UNIXY_i686-linux-android := 1
|
||||
CFG_LDPATH_i686-linux-android :=
|
||||
CFG_RUN_i686-linux-android=
|
||||
CFG_RUN_TARG_i686-linux-android=
|
||||
RUSTC_FLAGS_i686-linux-android :=
|
||||
RUSTC_CROSS_FLAGS_i686-linux-android :=
|
||||
CFG_GNU_TRIPLE_i686-linux-android := i686-linux-android
|
||||
@ -22,8 +22,3 @@ CFG_LDPATH_i686-pc-windows-msvc :=
|
||||
CFG_RUN_i686-pc-windows-msvc=$(2)
|
||||
CFG_RUN_TARG_i686-pc-windows-msvc=$(call CFG_RUN_i686-pc-windows-msvc,,$(2))
|
||||
CFG_GNU_TRIPLE_i686-pc-windows-msvc := i686-pc-win32
|
||||
|
||||
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
|
||||
# bootstrapping from itself. This is relevant during stage0, and other parts of
|
||||
# the build system take this into account.
|
||||
BOOTSTRAP_FROM_i686-pc-windows-msvc := i686-pc-windows-gnu
|
||||
|
||||
@ -22,8 +22,3 @@ CFG_LDPATH_x86_64-pc-windows-msvc :=
|
||||
CFG_RUN_x86_64-pc-windows-msvc=$(2)
|
||||
CFG_RUN_TARG_x86_64-pc-windows-msvc=$(call CFG_RUN_x86_64-pc-windows-msvc,,$(2))
|
||||
CFG_GNU_TRIPLE_x86_64-pc-windows-msvc := x86_64-pc-win32
|
||||
|
||||
# All windows nightiles are currently a GNU triple, so this MSVC triple is not
|
||||
# bootstrapping from itself. This is relevant during stage0, and other parts of
|
||||
# the build system take this into account.
|
||||
BOOTSTRAP_FROM_x86_64-pc-windows-msvc := x86_64-pc-windows-gnu
|
||||
|
||||
@ -101,7 +101,6 @@ define CLEAN_TARGET_STAGE_N
|
||||
clean$(1)_T_$(2)_H_$(3): \
|
||||
$$(foreach crate,$$(CRATES),clean$(1)_T_$(2)_H_$(3)-lib-$$(crate)) \
|
||||
$$(foreach tool,$$(TOOLS) $$(DEBUGGER_BIN_SCRIPTS_ALL),clean$(1)_T_$(2)_H_$(3)-tool-$$(tool))
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libmorestack.a
|
||||
$$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/libcompiler-rt.a
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/librun_pass_stage* # For unix
|
||||
$(Q)rm -f $$(TLIB$(1)_T_$(2)_H_$(3))/run_pass_stage* # For windows
|
||||
|
||||
52
mk/crates.mk
52
mk/crates.mk
@ -52,41 +52,44 @@
|
||||
TARGET_CRATES := libc std flate arena term \
|
||||
serialize getopts collections test rand \
|
||||
log graphviz core rbml alloc \
|
||||
rustc_unicode rustc_bitflags
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_unicode rustc_bitflags \
|
||||
alloc_system
|
||||
RUSTC_CRATES := rustc rustc_typeck rustc_mir rustc_borrowck rustc_resolve rustc_driver \
|
||||
rustc_trans rustc_back rustc_llvm rustc_privacy rustc_lint \
|
||||
rustc_data_structures
|
||||
rustc_data_structures rustc_front rustc_platform_intrinsics
|
||||
HOST_CRATES := syntax $(RUSTC_CRATES) rustdoc fmt_macros
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
TOOLS := compiletest rustdoc rustc rustbook error-index-generator
|
||||
|
||||
DEPS_core :=
|
||||
DEPS_libc := core
|
||||
DEPS_rustc_unicode := core
|
||||
DEPS_alloc := core libc native:jemalloc
|
||||
DEPS_alloc := core libc alloc_system
|
||||
DEPS_std := core libc rand alloc collections rustc_unicode \
|
||||
native:rust_builtin native:backtrace native:rustrt_native \
|
||||
rustc_bitflags
|
||||
native:rust_builtin native:backtrace \
|
||||
alloc_system
|
||||
DEPS_graphviz := std
|
||||
DEPS_syntax := std term serialize log fmt_macros arena libc
|
||||
DEPS_syntax := std term serialize log fmt_macros arena libc rustc_bitflags
|
||||
DEPS_rustc_driver := arena flate getopts graphviz libc rustc rustc_back rustc_borrowck \
|
||||
rustc_typeck rustc_resolve log syntax serialize rustc_llvm \
|
||||
rustc_trans rustc_privacy rustc_lint
|
||||
rustc_typeck rustc_mir rustc_resolve log syntax serialize rustc_llvm \
|
||||
rustc_trans rustc_privacy rustc_lint rustc_front
|
||||
|
||||
DEPS_rustc_trans := arena flate getopts graphviz libc rustc rustc_back \
|
||||
log syntax serialize rustc_llvm
|
||||
DEPS_rustc_typeck := rustc syntax
|
||||
DEPS_rustc_borrowck := rustc log graphviz syntax
|
||||
DEPS_rustc_resolve := rustc log syntax
|
||||
DEPS_rustc_privacy := rustc log syntax
|
||||
log syntax serialize rustc_llvm rustc_front rustc_platform_intrinsics
|
||||
DEPS_rustc_mir := rustc rustc_front syntax
|
||||
DEPS_rustc_typeck := rustc syntax rustc_front rustc_platform_intrinsics
|
||||
DEPS_rustc_borrowck := rustc rustc_front log graphviz syntax
|
||||
DEPS_rustc_resolve := rustc rustc_front log syntax
|
||||
DEPS_rustc_privacy := rustc rustc_front log syntax
|
||||
DEPS_rustc_lint := rustc log syntax
|
||||
DEPS_rustc := syntax flate arena serialize getopts rbml \
|
||||
log graphviz rustc_llvm rustc_back rustc_data_structures
|
||||
DEPS_rustc_llvm := native:rustllvm libc std
|
||||
DEPS_rustc_back := std syntax rustc_llvm flate log libc
|
||||
DEPS_rustc_llvm := native:rustllvm libc std rustc_bitflags
|
||||
DEPS_rustc_platform_intrinsics := rustc rustc_llvm
|
||||
DEPS_rustc_back := std syntax rustc_llvm rustc_front flate log libc
|
||||
DEPS_rustc_front := std syntax log serialize
|
||||
DEPS_rustc_data_structures := std log serialize
|
||||
DEPS_rustdoc := rustc rustc_driver native:hoedown serialize getopts \
|
||||
test rustc_lint
|
||||
test rustc_lint rustc_front
|
||||
DEPS_rustc_bitflags := core
|
||||
DEPS_flate := std native:miniz
|
||||
DEPS_arena := std
|
||||
@ -102,6 +105,7 @@ DEPS_test := std getopts serialize rbml term native:rust_test_helpers
|
||||
DEPS_rand := core
|
||||
DEPS_log := std
|
||||
DEPS_fmt_macros = std
|
||||
DEPS_alloc_system := core libc
|
||||
|
||||
TOOL_DEPS_compiletest := test getopts
|
||||
TOOL_DEPS_rustdoc := rustdoc
|
||||
@ -121,14 +125,26 @@ ONLY_RLIB_rand := 1
|
||||
ONLY_RLIB_collections := 1
|
||||
ONLY_RLIB_rustc_unicode := 1
|
||||
ONLY_RLIB_rustc_bitflags := 1
|
||||
ONLY_RLIB_alloc_system := 1
|
||||
|
||||
# Documented-by-default crates
|
||||
DOC_CRATES := std alloc collections core libc rustc_unicode
|
||||
|
||||
ifeq ($(CFG_DISABLE_JEMALLOC),)
|
||||
TARGET_CRATES += alloc_jemalloc
|
||||
DEPS_std += alloc_jemalloc
|
||||
DEPS_alloc_jemalloc := core libc native:jemalloc
|
||||
ONLY_RLIB_alloc_jemalloc := 1
|
||||
else
|
||||
RUSTFLAGS_rustc_back := --cfg disable_jemalloc
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# You should not need to edit below this line
|
||||
################################################################################
|
||||
|
||||
CRATES := $(TARGET_CRATES) $(HOST_CRATES)
|
||||
|
||||
# This macro creates some simple definitions for each crate being built, just
|
||||
# some munging of all of the parameters above.
|
||||
#
|
||||
|
||||
96
mk/docs.mk
96
mk/docs.mk
@ -13,9 +13,6 @@
|
||||
#
|
||||
# The DOCS variable is their names (with no file extension).
|
||||
#
|
||||
# PDF_DOCS lists the targets for which PDF documentation should be
|
||||
# build.
|
||||
#
|
||||
# RUSTDOC_FLAGS_xyz variables are extra arguments to pass to the
|
||||
# rustdoc invocation for xyz.
|
||||
#
|
||||
@ -35,8 +32,6 @@ DOCS += guide-crates guide-error-handling guide-ffi guide-macros guide \
|
||||
guide-testing
|
||||
|
||||
|
||||
PDF_DOCS := reference
|
||||
|
||||
RUSTDOC_DEPS_reference := doc/full-toc.inc
|
||||
RUSTDOC_FLAGS_reference := --html-in-header=doc/full-toc.inc
|
||||
|
||||
@ -48,17 +43,10 @@ L10N_LANGS := ja
|
||||
RUSTDOC_HTML_OPTS_NO_CSS = --html-before-content=doc/version_info.html \
|
||||
--html-in-header=doc/favicon.inc \
|
||||
--html-after-content=doc/footer.inc \
|
||||
--markdown-playground-url='http://play.rust-lang.org/'
|
||||
--markdown-playground-url='https://play.rust-lang.org/'
|
||||
|
||||
RUSTDOC_HTML_OPTS = $(RUSTDOC_HTML_OPTS_NO_CSS) --markdown-css rust.css
|
||||
|
||||
PANDOC_BASE_OPTS := --standalone --toc --number-sections
|
||||
PANDOC_TEX_OPTS = $(PANDOC_BASE_OPTS) --from=markdown --to=latex \
|
||||
--include-before-body=doc/version.tex \
|
||||
--include-before-body=doc/footer.tex \
|
||||
--include-in-header=doc/uptack.tex
|
||||
PANDOC_EPUB_OPTS = $(PANDOC_BASE_OPTS) --to=epub
|
||||
|
||||
# The rustdoc executable...
|
||||
RUSTDOC_EXE = $(HBIN2_H_$(CFG_BUILD))/rustdoc$(X_$(CFG_BUILD))
|
||||
# ...with rpath included in case --disable-rpath was provided to
|
||||
@ -89,30 +77,10 @@ else
|
||||
HTML_DEPS :=
|
||||
endif
|
||||
|
||||
# Check for xelatex
|
||||
|
||||
ifneq ($(CFG_XELATEX),)
|
||||
CFG_LATEX := $(CFG_XELATEX)
|
||||
XELATEX = 1
|
||||
else
|
||||
$(info cfg: no xelatex found, disabling LaTeX docs)
|
||||
NO_PDF_DOCS = 1
|
||||
endif
|
||||
|
||||
ifeq ($(CFG_PANDOC),)
|
||||
$(info cfg: no pandoc found, omitting PDF and EPUB docs)
|
||||
ONLY_HTML_DOCS = 1
|
||||
endif
|
||||
|
||||
|
||||
######################################################################
|
||||
# Rust version
|
||||
######################################################################
|
||||
|
||||
doc/version.tex: $(MKFILE_DEPS) $(wildcard $(D)/*.*) | doc/
|
||||
@$(call E, version-stamp: $@)
|
||||
$(Q)echo "$(CFG_VERSION)" >$@
|
||||
|
||||
HTML_DEPS += doc/version_info.html
|
||||
doc/version_info.html: $(D)/version_info.html.template $(MKFILE_DEPS) \
|
||||
$(wildcard $(D)/*.*) | doc/
|
||||
@ -121,10 +89,10 @@ doc/version_info.html: $(D)/version_info.html.template $(MKFILE_DEPS) \
|
||||
s/SHORT_HASH/$(CFG_SHORT_VER_HASH)/; \
|
||||
s/STAMP/$(CFG_VER_HASH)/;" $< >$@
|
||||
|
||||
GENERATED += doc/version.tex doc/version_info.html
|
||||
GENERATED += doc/version_info.html
|
||||
|
||||
######################################################################
|
||||
# Docs, from rustdoc and sometimes pandoc
|
||||
# Docs from rustdoc
|
||||
######################################################################
|
||||
|
||||
doc/:
|
||||
@ -150,26 +118,12 @@ doc/footer.inc: $(D)/footer.inc | doc/
|
||||
$(Q)cp -PRp $< $@ 2> /dev/null
|
||||
|
||||
# The (english) documentation for each doc item.
|
||||
|
||||
define DEF_SHOULD_BUILD_PDF_DOC
|
||||
SHOULD_BUILD_PDF_DOC_$(1) = 1
|
||||
endef
|
||||
$(foreach docname,$(PDF_DOCS),$(eval $(call DEF_SHOULD_BUILD_PDF_DOC,$(docname))))
|
||||
|
||||
doc/footer.tex: $(D)/footer.inc | doc/
|
||||
@$(call E, pandoc: $@)
|
||||
$(CFG_PANDOC) --from=html --to=latex $< --output=$@
|
||||
|
||||
doc/uptack.tex: $(D)/uptack.tex | doc/
|
||||
$(Q)cp $< $@
|
||||
|
||||
# HTML (rustdoc)
|
||||
DOC_TARGETS += doc/not_found.html
|
||||
doc/not_found.html: $(D)/not_found.md $(HTML_DEPS) | doc/
|
||||
@$(call E, rustdoc: $@)
|
||||
$(Q)$(RUSTDOC) $(RUSTDOC_HTML_OPTS_NO_CSS) \
|
||||
--markdown-no-toc \
|
||||
--markdown-css http://doc.rust-lang.org/rust.css $<
|
||||
--markdown-css https://doc.rust-lang.org/rust.css $<
|
||||
|
||||
define DEF_DOC
|
||||
|
||||
@ -179,47 +133,6 @@ doc/$(1).html: $$(D)/$(1).md $$(HTML_DEPS) $$(RUSTDOC_DEPS_$(1)) | doc/
|
||||
@$$(call E, rustdoc: $$@)
|
||||
$$(Q)$$(RUSTDOC) $$(RUSTDOC_HTML_OPTS) $$(RUSTDOC_FLAGS_$(1)) $$<
|
||||
|
||||
ifneq ($(ONLY_HTML_DOCS),1)
|
||||
|
||||
# EPUB (pandoc directly)
|
||||
DOC_TARGETS += doc/$(1).epub
|
||||
doc/$(1).epub: $$(D)/$(1).md | doc/
|
||||
@$$(call E, pandoc: $$@)
|
||||
$$(CFG_PANDOC) $$(PANDOC_EPUB_OPTS) $$< --output=$$@
|
||||
|
||||
# PDF (md =(pandoc)=> tex =(pdflatex)=> pdf)
|
||||
DOC_TARGETS += doc/$(1).tex
|
||||
doc/$(1).tex: $$(D)/$(1).md doc/uptack.tex doc/footer.tex doc/version.tex | doc/
|
||||
@$$(call E, pandoc: $$@)
|
||||
$$(CFG_PANDOC) $$(PANDOC_TEX_OPTS) $$< --output=$$@
|
||||
|
||||
ifneq ($(NO_PDF_DOCS),1)
|
||||
ifeq ($$(SHOULD_BUILD_PDF_DOC_$(1)),1)
|
||||
DOC_TARGETS += doc/$(1).pdf
|
||||
ifneq ($(XELATEX),1)
|
||||
doc/$(1).pdf: doc/$(1).tex
|
||||
@$$(call E, latex compiler: $$@)
|
||||
$$(Q)$$(CFG_LATEX) \
|
||||
-interaction=batchmode \
|
||||
-output-directory=doc \
|
||||
$$<
|
||||
else
|
||||
# The version of xelatex on the snap bots seemingly ingores -output-directory
|
||||
# So we'll output to . and move to the doc directory manually.
|
||||
# This will leave some intermediate files in the build directory.
|
||||
doc/$(1).pdf: doc/$(1).tex
|
||||
@$$(call E, latex compiler: $$@)
|
||||
$$(Q)$$(CFG_LATEX) \
|
||||
-interaction=batchmode \
|
||||
-output-directory=. \
|
||||
$$<
|
||||
$$(Q)mv ./$(1).pdf $$@
|
||||
endif # XELATEX
|
||||
endif # SHOULD_BUILD_PDF_DOCS_$(1)
|
||||
endif # NO_PDF_DOCS
|
||||
|
||||
endif # ONLY_HTML_DOCS
|
||||
|
||||
endef
|
||||
|
||||
$(foreach docname,$(DOCS),$(eval $(call DEF_DOC,$(docname))))
|
||||
@ -278,6 +191,7 @@ ifdef CFG_DISABLE_DOCS
|
||||
endif
|
||||
|
||||
docs: $(DOC_TARGETS)
|
||||
doc: docs
|
||||
compiler-docs: $(COMPILER_DOC_TARGETS)
|
||||
|
||||
trpl: doc/book/index.html
|
||||
|
||||
20
mk/main.mk
20
mk/main.mk
@ -13,12 +13,12 @@
|
||||
######################################################################
|
||||
|
||||
# The version number
|
||||
CFG_RELEASE_NUM=1.3.0
|
||||
CFG_RELEASE_NUM=1.4.0
|
||||
|
||||
# An optional number to put after the label, e.g. '.2' -> '-beta.2'
|
||||
# NB Make sure it starts with a dot to conform to semver pre-release
|
||||
# versions (section 9)
|
||||
CFG_PRERELEASE_VERSION=.3
|
||||
CFG_PRERELEASE_VERSION=.4
|
||||
|
||||
# Append a version-dependent hash to each library, so we can install different
|
||||
# versions in the same place
|
||||
@ -163,7 +163,7 @@ endif
|
||||
# that the snapshot will be generated with a statically linked rustc so we only
|
||||
# have to worry about the distribution of one file (with its native dynamic
|
||||
# dependencies)
|
||||
RUSTFLAGS_STAGE0 += -C prefer-dynamic
|
||||
RUSTFLAGS_STAGE0 += -C prefer-dynamic -C no-stack-check
|
||||
RUSTFLAGS_STAGE1 += -C prefer-dynamic
|
||||
RUST_LIB_FLAGS_ST2 += -C prefer-dynamic
|
||||
RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
|
||||
@ -172,6 +172,18 @@ RUST_LIB_FLAGS_ST3 += -C prefer-dynamic
|
||||
# by not emitting them.
|
||||
RUSTFLAGS_STAGE0 += -Z no-landing-pads
|
||||
|
||||
# Enable MIR to "always build" for crates where this works. This is
|
||||
# just temporary while MIR is being actively built up -- it's just a
|
||||
# poor man's unit testing infrastructure. Anyway we only want this for
|
||||
# stage1/stage2.
|
||||
define ADD_MIR_FLAG
|
||||
RUSTFLAGS1_$(1) += -Z always-build-mir
|
||||
RUSTFLAGS2_$(1) += -Z always-build-mir
|
||||
endef
|
||||
$(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
$(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
|
||||
# platform-specific auto-configuration
|
||||
include $(CFG_SRC_DIR)mk/platform.mk
|
||||
|
||||
@ -294,7 +306,7 @@ LLVM_VERSION_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --version)
|
||||
LLVM_BINDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --bindir)
|
||||
LLVM_INCDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --includedir)
|
||||
LLVM_LIBDIR_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --libdir)
|
||||
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L "$$(LLVM_LIBDIR_$(1))"
|
||||
LLVM_LIBDIR_RUSTFLAGS_$(1)=-L native="$$(LLVM_LIBDIR_$(1))"
|
||||
LLVM_LDFLAGS_$(1)=$$(shell "$$(LLVM_CONFIG_$(1))" --ldflags)
|
||||
ifeq ($$(findstring freebsd,$(1)),freebsd)
|
||||
# On FreeBSD, it may search wrong headers (that are for pre-installed LLVM),
|
||||
|
||||
@ -113,8 +113,7 @@ CFG_RLIB_GLOB=lib$(1)-*.rlib
|
||||
include $(wildcard $(CFG_SRC_DIR)mk/cfg/*.mk)
|
||||
|
||||
define ADD_INSTALLED_OBJECTS
|
||||
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),morestack) \
|
||||
$$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
INSTALLED_OBJECTS_$(1) += $$(call CFG_STATIC_LIB_NAME_$(1),compiler-rt)
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
@ -238,56 +237,3 @@ endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call CFG_MAKE_TOOLCHAIN,$(target))))
|
||||
|
||||
# There are more comments about this available in the target specification for
|
||||
# Windows MSVC in the compiler, but the gist of it is that we use `llvm-ar.exe`
|
||||
# instead of `lib.exe` for assembling archives, so we need to inject this custom
|
||||
# dependency here.
|
||||
define ADD_LLVM_AR_TO_MSVC_DEPS
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
NATIVE_TOOL_DEPS_core_T_$(1) += llvm-ar.exe
|
||||
INSTALLED_BINS_$(1) += llvm-ar.exe
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call ADD_LLVM_AR_TO_MSVC_DEPS,$(target))))
|
||||
|
||||
# When working with MSVC on windows, each DLL needs to explicitly declare its
|
||||
# interface to the outside world through some means. The options for doing so
|
||||
# include:
|
||||
#
|
||||
# 1. A custom attribute on each function itself
|
||||
# 2. A linker argument saying what to export
|
||||
# 3. A file which lists all symbols that need to be exported
|
||||
#
|
||||
# The Rust compiler takes care (1) for us for all Rust code by annotating all
|
||||
# public-facing functions with dllexport, but we have a few native dependencies
|
||||
# which need to cross the DLL boundary. The most important of these dependencies
|
||||
# is LLVM which is linked into `rustc_llvm.dll` but primarily used from
|
||||
# `rustc_trans.dll`. This means that many of LLVM's C API functions need to be
|
||||
# exposed from `rustc_llvm.dll` to be forwarded over the boundary.
|
||||
#
|
||||
# Unfortunately, at this time, LLVM does not handle this sort of exportation on
|
||||
# Windows for us, so we're forced to do it ourselves if we want it (which seems
|
||||
# like the path of least resistance right now). To do this we generate a `.DEF`
|
||||
# file [1] which we then custom-pass to the linker when building the rustc_llvm
|
||||
# crate. This DEF file list all symbols that are exported from
|
||||
# `src/librustc_llvm/lib.rs` and is generated by a small python script.
|
||||
#
|
||||
# Fun times!
|
||||
#
|
||||
# [1]: https://msdn.microsoft.com/en-us/library/28d6s79h.aspx
|
||||
define ADD_RUSTC_LLVM_DEF_TO_MSVC
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
RUSTFLAGS_rustc_llvm_T_$(1) += -C link-args="-DEF:$(1)/rt/rustc_llvm.def"
|
||||
CUSTOM_DEPS_rustc_llvm_T_$(1) += $(1)/rt/rustc_llvm.def
|
||||
|
||||
$(1)/rt/rustc_llvm.def: $$(S)src/etc/mklldef.py $$(S)src/librustc_llvm/lib.rs
|
||||
$$(CFG_PYTHON) $$^ $$@ rustc_llvm-$$(CFG_FILENAME_EXTRA)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(eval $(call ADD_RUSTC_LLVM_DEF_TO_MSVC,$(target))))
|
||||
|
||||
|
||||
35
mk/rt.mk
35
mk/rt.mk
@ -35,8 +35,7 @@
|
||||
# that's per-target so you're allowed to conditionally add files based on the
|
||||
# target.
|
||||
################################################################################
|
||||
NATIVE_LIBS := rust_builtin hoedown morestack miniz \
|
||||
rustrt_native rust_test_helpers
|
||||
NATIVE_LIBS := rust_builtin hoedown miniz rust_test_helpers
|
||||
|
||||
# $(1) is the target triple
|
||||
define NATIVE_LIBRARIES
|
||||
@ -53,10 +52,7 @@ NATIVE_DEPS_hoedown_$(1) := hoedown/src/autolink.c \
|
||||
NATIVE_DEPS_miniz_$(1) = miniz.c
|
||||
NATIVE_DEPS_rust_builtin_$(1) := rust_builtin.c \
|
||||
rust_android_dummy.c
|
||||
NATIVE_DEPS_rustrt_native_$(1) := arch/$$(HOST_$(1))/record_sp.S
|
||||
NATIVE_DEPS_rust_test_helpers_$(1) := rust_test_helpers.c
|
||||
NATIVE_DEPS_morestack_$(1) := arch/$$(HOST_$(1))/morestack.S
|
||||
|
||||
|
||||
################################################################################
|
||||
# You shouldn't find it that necessary to edit anything below this line.
|
||||
@ -188,8 +184,6 @@ $$(JEMALLOC_LOCAL_$(1)): $$(JEMALLOC_DEPS) $$(MKFILE_DEPS)
|
||||
EXTRA_CFLAGS="-g1 -ffunction-sections -fdata-sections"
|
||||
$$(Q)$$(MAKE) -C "$$(JEMALLOC_BUILD_DIR_$(1))" build_lib_static
|
||||
|
||||
ifeq ($$(CFG_DISABLE_JEMALLOC),)
|
||||
RUSTFLAGS_alloc := --cfg jemalloc
|
||||
ifeq ($(1),$$(CFG_BUILD))
|
||||
ifneq ($$(CFG_JEMALLOC_ROOT),)
|
||||
$$(JEMALLOC_LIB_$(1)): $$(CFG_JEMALLOC_ROOT)/libjemalloc_pic.a
|
||||
@ -203,10 +197,6 @@ else
|
||||
$$(JEMALLOC_LIB_$(1)): $$(JEMALLOC_LOCAL_$(1))
|
||||
$$(Q)cp $$< $$@
|
||||
endif
|
||||
else
|
||||
$$(JEMALLOC_LIB_$(1)): $$(MKFILE_DEPS)
|
||||
$$(Q)touch $$@
|
||||
endif
|
||||
|
||||
################################################################################
|
||||
# compiler-rt
|
||||
@ -269,8 +259,10 @@ BACKTRACE_NAME_$(1) := $$(call CFG_STATIC_LIB_NAME_$(1),backtrace)
|
||||
BACKTRACE_LIB_$(1) := $$(RT_OUTPUT_DIR_$(1))/$$(BACKTRACE_NAME_$(1))
|
||||
BACKTRACE_BUILD_DIR_$(1) := $$(RT_OUTPUT_DIR_$(1))/libbacktrace
|
||||
|
||||
# We don't use this on platforms that aren't linux-based, so just make the file
|
||||
# available, the compilation of libstd won't actually build it.
|
||||
# We don't use this on platforms that aren't linux-based (with the exception of
|
||||
# msys2/mingw builds on windows, which use it to read the dwarf debug
|
||||
# information) so just make the file available, the compilation of libstd won't
|
||||
# actually build it.
|
||||
ifeq ($$(findstring darwin,$$(OSTYPE_$(1))),darwin)
|
||||
# See comment above
|
||||
$$(BACKTRACE_LIB_$(1)):
|
||||
@ -283,7 +275,7 @@ $$(BACKTRACE_LIB_$(1)):
|
||||
touch $$@
|
||||
else
|
||||
|
||||
ifeq ($$(CFG_WINDOWSY_$(1)),1)
|
||||
ifeq ($$(findstring msvc,$(1)),msvc)
|
||||
# See comment above
|
||||
$$(BACKTRACE_LIB_$(1)):
|
||||
touch $$@
|
||||
@ -306,16 +298,25 @@ endif
|
||||
# ./configure script. This is done to force libbacktrace to *not* use the
|
||||
# atomic/sync functionality because it pulls in unnecessary dependencies and we
|
||||
# never use it anyway.
|
||||
#
|
||||
# We also use `env PWD=` to clear the PWD environment variable, and then
|
||||
# execute the command in a new shell. This is necessary to workaround a
|
||||
# buildbot/msys2 bug: the shell is launched with PWD set to a windows-style path,
|
||||
# which results in all further uses of `pwd` also printing a windows-style path,
|
||||
# which breaks libbacktrace's configure script. Clearing PWD within the same
|
||||
# shell is not sufficient.
|
||||
|
||||
$$(BACKTRACE_BUILD_DIR_$(1))/Makefile: $$(BACKTRACE_DEPS) $$(MKFILE_DEPS)
|
||||
@$$(call E, configure: libbacktrace for $(1))
|
||||
$$(Q)rm -rf $$(BACKTRACE_BUILD_DIR_$(1))
|
||||
$$(Q)mkdir -p $$(BACKTRACE_BUILD_DIR_$(1))
|
||||
$$(Q)(cd $$(BACKTRACE_BUILD_DIR_$(1)) && \
|
||||
$$(Q)(cd $$(BACKTRACE_BUILD_DIR_$(1)) && env \
|
||||
PWD= \
|
||||
CC="$$(CC_$(1))" \
|
||||
AR="$$(AR_$(1))" \
|
||||
RANLIB="$$(AR_$(1)) s" \
|
||||
CFLAGS="$$(CFG_GCCISH_CFLAGS_$(1):-Werror=) -fno-stack-protector" \
|
||||
$(S)src/libbacktrace/configure --target=$(1) --host=$(CFG_BUILD))
|
||||
$(S)src/libbacktrace/configure --build=$(CFG_GNU_TRIPLE_$(CFG_BUILD)) --host=$(CFG_GNU_TRIPLE_$(1)))
|
||||
$$(Q)echo '#undef HAVE_ATOMIC_FUNCTIONS' >> \
|
||||
$$(BACKTRACE_BUILD_DIR_$(1))/config.h
|
||||
$$(Q)echo '#undef HAVE_SYNC_FUNCTIONS' >> \
|
||||
@ -327,7 +328,7 @@ $$(BACKTRACE_LIB_$(1)): $$(BACKTRACE_BUILD_DIR_$(1))/Makefile $$(MKFILE_DEPS)
|
||||
INCDIR=$(S)src/libbacktrace
|
||||
$$(Q)cp $$(BACKTRACE_BUILD_DIR_$(1))/.libs/libbacktrace.a $$@
|
||||
|
||||
endif # endif for windowsy
|
||||
endif # endif for msvc
|
||||
endif # endif for ios
|
||||
endif # endif for darwin
|
||||
|
||||
|
||||
97
mk/target.mk
97
mk/target.mk
@ -13,6 +13,10 @@
|
||||
# this exists can be found on issue #2400
|
||||
export CFG_COMPILER_HOST_TRIPLE
|
||||
|
||||
# Used as defaults for the runtime ar and cc tools
|
||||
export CFG_DEFAULT_LINKER
|
||||
export CFG_DEFAULT_AR
|
||||
|
||||
# The standard libraries should be held up to a higher standard than any old
|
||||
# code, make sure that these common warnings are denied by default. These can
|
||||
# be overridden during development temporarily. For stage0, we allow warnings
|
||||
@ -37,10 +41,7 @@ CRATE_FULLDEPS_$(1)_T_$(2)_H_$(3)_$(4) := \
|
||||
$$(foreach dep,$$(NATIVE_DEPS_$(4)), \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(call CFG_STATIC_LIB_NAME_$(2),$$(dep))) \
|
||||
$$(foreach dep,$$(NATIVE_DEPS_$(4)_T_$(2)), \
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(dep)) \
|
||||
$$(foreach dep,$$(NATIVE_TOOL_DEPS_$(4)_T_$(2)), \
|
||||
$$(TBIN$(1)_T_$(3)_H_$(3))/$$(dep)) \
|
||||
$$(CUSTOM_DEPS_$(4)_T_$(2))
|
||||
$$(RT_OUTPUT_DIR_$(2))/$$(dep))
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
@ -56,8 +57,7 @@ $(foreach host,$(CFG_HOST), \
|
||||
# 1. The immediate dependencies are the rust source files
|
||||
# 2. Each rust crate dependency is listed (based on their stamp files),
|
||||
# as well as all native dependencies (listed in RT_OUTPUT_DIR)
|
||||
# 3. The stage (n-1) compiler is required through the TSREQ dependency, along
|
||||
# with the morestack library
|
||||
# 3. The stage (n-1) compiler is required through the TSREQ dependency
|
||||
# 4. When actually executing the rule, the first thing we do is to clean out
|
||||
# old libs and rlibs via the REMOVE_ALL_OLD_GLOB_MATCHES macro
|
||||
# 5. Finally, we get around to building the actual crate. It's just one
|
||||
@ -93,7 +93,8 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
$$(LLVM_LIBDIR_RUSTFLAGS_$(2)) \
|
||||
$$(LLVM_STDCPP_RUSTFLAGS_$(2)) \
|
||||
$$(RUSTFLAGS_$(4)) \
|
||||
$$(RUSTFLAGS_$(4)_T_$(2)) \
|
||||
$$(RUSTFLAGS$(1)_$(4)) \
|
||||
$$(RUSTFLAGS$(1)_$(4)_T_$(2)) \
|
||||
--out-dir $$(@D) \
|
||||
-C extra-filename=-$$(CFG_FILENAME_EXTRA) \
|
||||
$$<
|
||||
@ -143,9 +144,6 @@ SNAPSHOT_RUSTC_POST_CLEANUP=$(HBIN0_H_$(CFG_BUILD))/rustc$(X_$(CFG_BUILD))
|
||||
|
||||
define TARGET_HOST_RULES
|
||||
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/:
|
||||
mkdir -p $$@
|
||||
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/:
|
||||
mkdir -p $$@
|
||||
|
||||
@ -153,11 +151,6 @@ $$(TLIB$(1)_T_$(2)_H_$(3))/%: $$(RT_OUTPUT_DIR_$(2))/% \
|
||||
| $$(TLIB$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
|
||||
@$$(call E, cp: $$@)
|
||||
$$(Q)cp $$< $$@
|
||||
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/%: $$(CFG_LLVM_INST_DIR_$(2))/bin/% \
|
||||
| $$(TBIN$(1)_T_$(2)_H_$(3))/ $$(SNAPSHOT_RUSTC_POST_CLEANUP)
|
||||
@$$(call E, cp: $$@)
|
||||
$$(Q)cp $$< $$@
|
||||
endef
|
||||
|
||||
$(foreach source,$(CFG_HOST), \
|
||||
@ -181,77 +174,3 @@ $(foreach host,$(CFG_HOST), \
|
||||
$(foreach stage,$(STAGES), \
|
||||
$(foreach tool,$(TOOLS), \
|
||||
$(eval $(call TARGET_TOOL,$(stage),$(target),$(host),$(tool)))))))
|
||||
|
||||
# We have some triples which are bootstrapped from other triples, and this means
|
||||
# that we need to fixup some of the native tools that a triple depends on.
|
||||
#
|
||||
# For example, MSVC requires the llvm-ar.exe executable to manage archives, but
|
||||
# it bootstraps from the GNU Windows triple. This means that the compiler will
|
||||
# add this directory to PATH when executing new processes:
|
||||
#
|
||||
# $SYSROOT/rustlib/x86_64-pc-windows-gnu/bin
|
||||
#
|
||||
# Unfortunately, however, the GNU triple is not known about in stage0, so the
|
||||
# tools are actually located in:
|
||||
#
|
||||
# $SYSROOT/rustlib/x86_64-pc-windows-msvc/bin
|
||||
#
|
||||
# To remedy this problem, the rules below copy all native tool dependencies into
|
||||
# the bootstrap triple's location in stage 0 so the bootstrap compiler can find
|
||||
# the right sets of tools. Later stages (1+) will have the right host triple for
|
||||
# the compiler, so there's no need to worry there.
|
||||
#
|
||||
# $(1) - stage
|
||||
# $(2) - triple that's being used as host/target
|
||||
# $(3) - triple snapshot is built for
|
||||
# $(4) - crate
|
||||
# $(5) - tool
|
||||
define MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR
|
||||
ifneq (,$(3))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(2))/stamp.$(4): $$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5)
|
||||
|
||||
$$(HLIB$(1)_H_$(2))/rustlib/$(3)/bin/$(5): $$(TBIN$(1)_T_$(2)_H_$(2))/$(5)
|
||||
mkdir -p $$(@D)
|
||||
cp $$< $$@
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach crate,$(CRATES), \
|
||||
$(foreach tool,$(NATIVE_TOOL_DEPS_$(crate)_T_$(target)), \
|
||||
$(eval $(call MOVE_TOOLS_TO_SNAPSHOT_HOST_DIR,0,$(target),$(BOOTSTRAP_FROM_$(target)),$(crate),$(tool))))))
|
||||
|
||||
# For MSVC targets we need to set up some environment variables for the linker
|
||||
# to work correctly when building Rust crates. These two variables are:
|
||||
#
|
||||
# - LIB tells the linker the default search path for finding system libraries,
|
||||
# for example kernel32.dll
|
||||
# - PATH needs to be modified to ensure that MSVC's link.exe is first in the
|
||||
# path instead of MinGW's /usr/bin/link.exe (entirely unrelated)
|
||||
#
|
||||
# The values for these variables are detected by the configure script.
|
||||
define SETUP_LIB_MSVC_ENV_VARS
|
||||
ifeq ($$(findstring msvc,$(2)),msvc)
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
|
||||
$$(TLIB$(1)_T_$(2)_H_$(3))/stamp.$(4): \
|
||||
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
|
||||
endif
|
||||
endef
|
||||
define SETUP_TOOL_MSVC_ENV_VARS
|
||||
ifeq ($$(findstring msvc,$(2)),msvc)
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
export LIB := $$(CFG_MSVC_LIB_PATH_$$(HOST_$(2)))
|
||||
$$(TBIN$(1)_T_$(2)_H_$(3))/$(4)$$(X_$(2)): \
|
||||
export PATH := $$(CFG_MSVC_BINDIR_$$(HOST_$(2))):$$(PATH)
|
||||
endif
|
||||
endef
|
||||
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach crate,$(CRATES), \
|
||||
$(eval $(call SETUP_LIB_MSVC_ENV_VARS,0,$(target),$(host),$(crate))))))
|
||||
$(foreach host,$(CFG_HOST), \
|
||||
$(foreach target,$(CFG_TARGET), \
|
||||
$(foreach tool,$(TOOLS), \
|
||||
$(eval $(call SETUP_TOOL_MSVC_ENV_VARS,0,$(target),$(host),$(tool))))))
|
||||
|
||||
18
mk/tests.mk
18
mk/tests.mk
@ -22,7 +22,8 @@ $(eval $(call RUST_CRATE,coretest))
|
||||
DEPS_collectionstest :=
|
||||
$(eval $(call RUST_CRATE,collectionstest))
|
||||
|
||||
TEST_TARGET_CRATES = $(filter-out core rustc_unicode,$(TARGET_CRATES)) \
|
||||
TEST_TARGET_CRATES = $(filter-out core rustc_unicode alloc_system \
|
||||
alloc_jemalloc,$(TARGET_CRATES)) \
|
||||
collectionstest coretest
|
||||
TEST_DOC_CRATES = $(DOC_CRATES)
|
||||
TEST_HOST_CRATES = $(filter-out rustc_typeck rustc_borrowck rustc_resolve \
|
||||
@ -95,7 +96,8 @@ ifdef CFG_WINDOWSY_$(1)
|
||||
$$(if $$(findstring stage3,$$(1)), \
|
||||
stage3/$$(CFG_LIBDIR_RELATIVE), \
|
||||
)))))/rustlib/$$(CFG_BUILD)/lib
|
||||
CFG_RUN_TEST_$(1)=$$(call CFG_RUN_$(1),$$(call CFG_TESTLIB_$(1),$$(1),$$(4)),$$(1))
|
||||
CFG_RUN_TEST_$(1)=$$(TARGET_RPATH_VAR$$(2)_T_$$(3)_H_$$(4)) \
|
||||
$$(call CFG_RUN_$(1),$$(call CFG_TESTLIB_$(1),$$(1),$$(4)),$$(1))
|
||||
endif
|
||||
|
||||
# Run the compiletest runner itself under valgrind
|
||||
@ -267,9 +269,10 @@ tidy-basic:
|
||||
.PHONY: tidy-binaries
|
||||
tidy-binaries:
|
||||
@$(call E, check: binaries)
|
||||
$(Q)find $(S)src -type f -perm +a+x \
|
||||
$(Q)find $(S)src -type f \
|
||||
\( -perm -u+x -or -perm -g+x -or -perm -o+x \) \
|
||||
-not -name '*.rs' -and -not -name '*.py' \
|
||||
-and -not -name '*.sh' \
|
||||
-and -not -name '*.sh' -and -not -name '*.pp' \
|
||||
| grep '^$(S)src/jemalloc' -v \
|
||||
| grep '^$(S)src/libuv' -v \
|
||||
| grep '^$(S)src/llvm' -v \
|
||||
@ -596,6 +599,10 @@ CTEST_DISABLE_debuginfo-gdb =
|
||||
CTEST_DISABLE_debuginfo-lldb = "lldb tests are disabled on android"
|
||||
endif
|
||||
|
||||
ifeq ($(findstring msvc,$(CFG_TARGET)),msvc)
|
||||
CTEST_DISABLE_debuginfo-gdb = "gdb tests are disabled on MSVC"
|
||||
endif
|
||||
|
||||
# CTEST_DISABLE_NONSELFHOST_$(TEST_GROUP), if set, will cause that
|
||||
# test group to be disabled *unless* the target is able to build a
|
||||
# compiler (i.e. when the target triple is in the set of of host
|
||||
@ -1049,7 +1056,8 @@ $(3)/test/run-make/%-$(1)-T-$(2)-H-$(3).ok: \
|
||||
$$(MAKE) \
|
||||
$$(HBIN$(1)_H_$(3))/rustc$$(X_$(3)) \
|
||||
$(3)/test/run-make/$$* \
|
||||
"$$(CC_$(3)) $$(CFG_GCCISH_CFLAGS_$(3))" \
|
||||
$$(CC_$(3)) \
|
||||
"$$(CFG_GCCISH_CFLAGS_$(3))" \
|
||||
$$(HBIN$(1)_H_$(3))/rustdoc$$(X_$(3)) \
|
||||
"$$(TESTNAME)" \
|
||||
$$(LD_LIBRARY_PATH_ENV_NAME$(1)_T_$(2)_H_$(3)) \
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#![feature(str_char)]
|
||||
#![feature(test)]
|
||||
#![feature(vec_push_all)]
|
||||
#![feature(path_components_peek)]
|
||||
|
||||
#![deny(warnings)]
|
||||
|
||||
@ -177,7 +178,7 @@ pub fn log_config(config: &Config) {
|
||||
logv(c, format!("filter: {}",
|
||||
opt_str(&config.filter
|
||||
.as_ref()
|
||||
.map(|re| re.to_string()))));
|
||||
.map(|re| re.to_owned()))));
|
||||
logv(c, format!("runtool: {}", opt_str(&config.runtool)));
|
||||
logv(c, format!("host-rustcflags: {}",
|
||||
opt_str(&config.host_rustcflags)));
|
||||
@ -204,19 +205,16 @@ pub fn opt_str<'a>(maybestr: &'a Option<String>) -> &'a str {
|
||||
|
||||
pub fn opt_str2(maybestr: Option<String>) -> String {
|
||||
match maybestr {
|
||||
None => "(none)".to_string(),
|
||||
None => "(none)".to_owned(),
|
||||
Some(s) => s,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run_tests(config: &Config) {
|
||||
if config.target.contains("android") {
|
||||
match config.mode {
|
||||
DebugInfoGdb => {
|
||||
println!("{} debug-info test uses tcp 5039 port.\
|
||||
please reserve it", config.target);
|
||||
}
|
||||
_ =>{}
|
||||
if let DebugInfoGdb = config.mode {
|
||||
println!("{} debug-info test uses tcp 5039 port.\
|
||||
please reserve it", config.target);
|
||||
}
|
||||
|
||||
// android debug-info test uses remote debugger
|
||||
@ -288,10 +286,10 @@ pub fn is_test(config: &Config, testfile: &Path) -> bool {
|
||||
// Pretty-printer does not work with .rc files yet
|
||||
let valid_extensions =
|
||||
match config.mode {
|
||||
Pretty => vec!(".rs".to_string()),
|
||||
_ => vec!(".rc".to_string(), ".rs".to_string())
|
||||
Pretty => vec!(".rs".to_owned()),
|
||||
_ => vec!(".rc".to_owned(), ".rs".to_owned())
|
||||
};
|
||||
let invalid_prefixes = vec!(".".to_string(), "#".to_string(), "~".to_string());
|
||||
let invalid_prefixes = vec!(".".to_owned(), "#".to_owned(), "~".to_owned());
|
||||
let name = testfile.file_name().unwrap().to_str().unwrap();
|
||||
|
||||
let mut valid = false;
|
||||
@ -363,7 +361,7 @@ fn extract_gdb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
full_version_line.char_at(pos + 3).is_digit(10) {
|
||||
continue
|
||||
}
|
||||
return Some(full_version_line[pos..pos+3].to_string());
|
||||
return Some(full_version_line[pos..pos+3].to_owned());
|
||||
}
|
||||
println!("Could not extract GDB version from line '{}'",
|
||||
full_version_line);
|
||||
@ -385,9 +383,8 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
// We are only interested in the major version number, so this function
|
||||
// will return `Some("179")` and `Some("300")` respectively.
|
||||
|
||||
match full_version_line {
|
||||
Some(ref full_version_line)
|
||||
if !full_version_line.trim().is_empty() => {
|
||||
if let Some(ref full_version_line) = full_version_line {
|
||||
if !full_version_line.trim().is_empty() {
|
||||
let full_version_line = full_version_line.trim();
|
||||
|
||||
for (pos, l) in full_version_line.char_indices() {
|
||||
@ -409,8 +406,7 @@ fn extract_lldb_version(full_version_line: Option<String>) -> Option<String> {
|
||||
}
|
||||
println!("Could not extract LLDB version from line '{}'",
|
||||
full_version_line);
|
||||
None
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ fn parse_expected(last_nonfollow_error: Option<usize>,
|
||||
let letters = line[kind_start..].chars();
|
||||
let msg = letters.skip_while(|c| c.is_whitespace())
|
||||
.skip_while(|c| !c.is_whitespace())
|
||||
.collect::<String>().trim().to_string();
|
||||
.collect::<String>().trim().to_owned();
|
||||
|
||||
let (which, line) = if follow {
|
||||
assert!(adjusts == 0, "use either //~| or //~^, not both.");
|
||||
|
||||
@ -67,10 +67,9 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
||||
let mut pretty_compare_only = false;
|
||||
let mut forbid_output = Vec::new();
|
||||
iter_header(testfile, &mut |ln| {
|
||||
match parse_error_pattern(ln) {
|
||||
Some(ep) => error_patterns.push(ep),
|
||||
None => ()
|
||||
};
|
||||
if let Some(ep) = parse_error_pattern(ln) {
|
||||
error_patterns.push(ep);
|
||||
}
|
||||
|
||||
if compile_flags.is_none() {
|
||||
compile_flags = parse_compile_flags(ln);
|
||||
@ -108,24 +107,20 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
||||
pretty_compare_only = parse_pretty_compare_only(ln);
|
||||
}
|
||||
|
||||
match parse_aux_build(ln) {
|
||||
Some(ab) => { aux_builds.push(ab); }
|
||||
None => {}
|
||||
if let Some(ab) = parse_aux_build(ln) {
|
||||
aux_builds.push(ab);
|
||||
}
|
||||
|
||||
match parse_exec_env(ln) {
|
||||
Some(ee) => { exec_env.push(ee); }
|
||||
None => {}
|
||||
if let Some(ee) = parse_exec_env(ln) {
|
||||
exec_env.push(ee);
|
||||
}
|
||||
|
||||
match parse_check_line(ln) {
|
||||
Some(cl) => check_lines.push(cl),
|
||||
None => ()
|
||||
};
|
||||
if let Some(cl) = parse_check_line(ln) {
|
||||
check_lines.push(cl);
|
||||
}
|
||||
|
||||
match parse_forbid_output(ln) {
|
||||
Some(of) => forbid_output.push(of),
|
||||
None => (),
|
||||
if let Some(of) = parse_forbid_output(ln) {
|
||||
forbid_output.push(of);
|
||||
}
|
||||
|
||||
true
|
||||
@ -134,8 +129,8 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
||||
for key in vec!["RUST_TEST_NOCAPTURE", "RUST_TEST_THREADS"] {
|
||||
match env::var(key) {
|
||||
Ok(val) =>
|
||||
if exec_env.iter().find(|&&(ref x, _)| *x == key.to_string()).is_none() {
|
||||
exec_env.push((key.to_string(), val))
|
||||
if exec_env.iter().find(|&&(ref x, _)| *x == key).is_none() {
|
||||
exec_env.push((key.to_owned(), val))
|
||||
},
|
||||
Err(..) => {}
|
||||
}
|
||||
@ -153,7 +148,7 @@ pub fn load_props(testfile: &Path) -> TestProps {
|
||||
check_stdout: check_stdout,
|
||||
no_prefer_dynamic: no_prefer_dynamic,
|
||||
pretty_expanded: pretty_expanded,
|
||||
pretty_mode: pretty_mode.unwrap_or("normal".to_string()),
|
||||
pretty_mode: pretty_mode.unwrap_or("normal".to_owned()),
|
||||
pretty_compare_only: pretty_compare_only,
|
||||
forbid_output: forbid_output,
|
||||
}
|
||||
@ -182,22 +177,21 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
match config.gdb_version {
|
||||
Some(ref actual_version) => {
|
||||
if line.contains("min-gdb-version") {
|
||||
let min_version = line.trim()
|
||||
.split(' ')
|
||||
.last()
|
||||
.expect("Malformed GDB version directive");
|
||||
// Ignore if actual version is smaller the minimum required
|
||||
// version
|
||||
gdb_version_to_int(actual_version) <
|
||||
gdb_version_to_int(min_version)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
if let Some(ref actual_version) = config.gdb_version {
|
||||
if line.contains("min-gdb-version") {
|
||||
let min_version = line.trim()
|
||||
.split(' ')
|
||||
.last()
|
||||
.expect("Malformed GDB version directive");
|
||||
// Ignore if actual version is smaller the minimum required
|
||||
// version
|
||||
gdb_version_to_int(actual_version) <
|
||||
gdb_version_to_int(min_version)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
None => false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -210,22 +204,21 @@ pub fn is_test_ignored(config: &Config, testfile: &Path) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
match config.lldb_version {
|
||||
Some(ref actual_version) => {
|
||||
if line.contains("min-lldb-version") {
|
||||
let min_version = line.trim()
|
||||
.split(' ')
|
||||
.last()
|
||||
.expect("Malformed lldb version directive");
|
||||
// Ignore if actual version is smaller the minimum required
|
||||
// version
|
||||
lldb_version_to_int(actual_version) <
|
||||
lldb_version_to_int(min_version)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
if let Some(ref actual_version) = config.lldb_version {
|
||||
if line.contains("min-lldb-version") {
|
||||
let min_version = line.trim()
|
||||
.split(' ')
|
||||
.last()
|
||||
.expect("Malformed lldb version directive");
|
||||
// Ignore if actual version is smaller the minimum required
|
||||
// version
|
||||
lldb_version_to_int(actual_version) <
|
||||
lldb_version_to_int(min_version)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
None => false
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
@ -316,11 +309,11 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
|
||||
// nv is either FOO or FOO=BAR
|
||||
let mut strs: Vec<String> = nv
|
||||
.splitn(2, '=')
|
||||
.map(|s| s.to_string())
|
||||
.map(str::to_owned)
|
||||
.collect();
|
||||
|
||||
match strs.len() {
|
||||
1 => (strs.pop().unwrap(), "".to_string()),
|
||||
1 => (strs.pop().unwrap(), "".to_owned()),
|
||||
2 => {
|
||||
let end = strs.pop().unwrap();
|
||||
(strs.pop().unwrap(), end)
|
||||
@ -331,33 +324,31 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
|
||||
}
|
||||
|
||||
fn parse_pp_exact(line: &str, testfile: &Path) -> Option<PathBuf> {
|
||||
match parse_name_value_directive(line, "pp-exact") {
|
||||
Some(s) => Some(PathBuf::from(&s)),
|
||||
None => {
|
||||
if let Some(s) = parse_name_value_directive(line, "pp-exact") {
|
||||
Some(PathBuf::from(&s))
|
||||
} else {
|
||||
if parse_name_directive(line, "pp-exact") {
|
||||
testfile.file_name().map(|s| PathBuf::from(s))
|
||||
testfile.file_name().map(PathBuf::from)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_name_directive(line: &str, directive: &str) -> bool {
|
||||
// This 'no-' rule is a quick hack to allow pretty-expanded and no-pretty-expanded to coexist
|
||||
line.contains(directive) && !line.contains(&("no-".to_string() + directive))
|
||||
line.contains(directive) && !line.contains(&("no-".to_owned() + directive))
|
||||
}
|
||||
|
||||
pub fn parse_name_value_directive(line: &str, directive: &str)
|
||||
-> Option<String> {
|
||||
let keycolon = format!("{}:", directive);
|
||||
match line.find(&keycolon) {
|
||||
Some(colon) => {
|
||||
let value = line[(colon + keycolon.len()) .. line.len()].to_string();
|
||||
debug!("{}: {}", directive, value);
|
||||
Some(value)
|
||||
}
|
||||
None => None
|
||||
if let Some(colon) = line.find(&keycolon) {
|
||||
let value = line[(colon + keycolon.len()) .. line.len()].to_owned();
|
||||
debug!("{}: {}", directive, value);
|
||||
Some(value)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -17,17 +17,15 @@ fn add_target_env(cmd: &mut Command, lib_path: &str, aux_path: Option<&str>) {
|
||||
// Need to be sure to put both the lib_path and the aux path in the dylib
|
||||
// search path for the child.
|
||||
let mut path = DynamicLibrary::search_path();
|
||||
match aux_path {
|
||||
Some(p) => path.insert(0, PathBuf::from(p)),
|
||||
None => {}
|
||||
if let Some(p) = aux_path {
|
||||
path.insert(0, PathBuf::from(p))
|
||||
}
|
||||
path.insert(0, PathBuf::from(lib_path));
|
||||
|
||||
// Add the new dylib search path var
|
||||
let var = DynamicLibrary::envvar();
|
||||
let newpath = DynamicLibrary::create_path(&path);
|
||||
let newpath = newpath.to_str().unwrap().to_string();
|
||||
cmd.env(var, &newpath);
|
||||
cmd.env(var, newpath);
|
||||
}
|
||||
|
||||
pub struct Result {pub status: ExitStatus, pub out: String, pub err: String}
|
||||
|
||||
@ -25,7 +25,7 @@ use std::fs::{self, File};
|
||||
use std::io::BufReader;
|
||||
use std::io::prelude::*;
|
||||
use std::net::TcpStream;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::path::{Path, PathBuf, Component};
|
||||
use std::process::{Command, Output, ExitStatus};
|
||||
|
||||
pub fn run(config: Config, testfile: &Path) {
|
||||
@ -165,9 +165,9 @@ fn run_valgrind_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
|
||||
fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
if props.pp_exact.is_some() {
|
||||
logv(config, "testing for exact pretty-printing".to_string());
|
||||
logv(config, "testing for exact pretty-printing".to_owned());
|
||||
} else {
|
||||
logv(config, "testing for converging pretty-printing".to_string());
|
||||
logv(config, "testing for converging pretty-printing".to_owned());
|
||||
}
|
||||
|
||||
let rounds =
|
||||
@ -183,7 +183,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let proc_res = print_source(config,
|
||||
props,
|
||||
testfile,
|
||||
srcs[round].to_string(),
|
||||
srcs[round].to_owned(),
|
||||
&props.pretty_mode);
|
||||
|
||||
if !proc_res.status.success() {
|
||||
@ -209,9 +209,9 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
|
||||
if props.pp_exact.is_some() {
|
||||
// Now we have to care about line endings
|
||||
let cr = "\r".to_string();
|
||||
actual = actual.replace(&cr, "").to_string();
|
||||
expected = expected.replace(&cr, "").to_string();
|
||||
let cr = "\r".to_owned();
|
||||
actual = actual.replace(&cr, "").to_owned();
|
||||
expected = expected.replace(&cr, "").to_owned();
|
||||
}
|
||||
|
||||
compare_source(&expected, &actual);
|
||||
@ -253,7 +253,7 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
make_pp_args(config,
|
||||
props,
|
||||
testfile,
|
||||
pretty_type.to_string()),
|
||||
pretty_type.to_owned()),
|
||||
props.exec_env.clone(),
|
||||
&config.compile_lib_path,
|
||||
Some(aux_dir.to_str().unwrap()),
|
||||
@ -266,17 +266,17 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
pretty_type: String) -> ProcArgs {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!("-".to_string(),
|
||||
"-Zunstable-options".to_string(),
|
||||
"--pretty".to_string(),
|
||||
let mut args = vec!("-".to_owned(),
|
||||
"-Zunstable-options".to_owned(),
|
||||
"--unpretty".to_owned(),
|
||||
pretty_type,
|
||||
format!("--target={}", config.target),
|
||||
"-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
"-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned());
|
||||
args.extend(split_maybe_args(&config.target_rustcflags));
|
||||
args.extend(split_maybe_args(&props.compile_flags));
|
||||
return ProcArgs {
|
||||
prog: config.rustc_path.to_str().unwrap().to_string(),
|
||||
prog: config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args: args,
|
||||
};
|
||||
}
|
||||
@ -313,19 +313,18 @@ actual:\n\
|
||||
&*config.target
|
||||
};
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!("-".to_string(),
|
||||
"-Zno-trans".to_string(),
|
||||
"--crate-type=lib".to_string(),
|
||||
let mut args = vec!("-".to_owned(),
|
||||
"-Zno-trans".to_owned(),
|
||||
format!("--target={}", target),
|
||||
"-L".to_string(),
|
||||
config.build_base.to_str().unwrap().to_string(),
|
||||
"-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
"-L".to_owned(),
|
||||
config.build_base.to_str().unwrap().to_owned(),
|
||||
"-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned());
|
||||
args.extend(split_maybe_args(&config.target_rustcflags));
|
||||
args.extend(split_maybe_args(&props.compile_flags));
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
return ProcArgs {
|
||||
prog: config.rustc_path.to_str().unwrap().to_string(),
|
||||
prog: config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args: args,
|
||||
};
|
||||
}
|
||||
@ -388,24 +387,24 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
&config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"push".to_string(),
|
||||
exe_file.to_str().unwrap().to_string(),
|
||||
"push".to_owned(),
|
||||
exe_file.to_str().unwrap().to_owned(),
|
||||
config.adb_test_dir.clone()
|
||||
],
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{:?}`", config.adb_path));
|
||||
|
||||
procsrv::run("",
|
||||
&config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"forward".to_string(),
|
||||
"tcp:5039".to_string(),
|
||||
"tcp:5039".to_string()
|
||||
"forward".to_owned(),
|
||||
"tcp:5039".to_owned(),
|
||||
"tcp:5039".to_owned()
|
||||
],
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{:?}`", config.adb_path));
|
||||
|
||||
let adb_arg = format!("export LD_LIBRARY_PATH={}; \
|
||||
@ -422,12 +421,12 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
,
|
||||
None,
|
||||
&[
|
||||
"shell".to_string(),
|
||||
"shell".to_owned(),
|
||||
adb_arg.clone()
|
||||
],
|
||||
vec!(("".to_string(),
|
||||
"".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(),
|
||||
"".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{:?}`", config.adb_path));
|
||||
loop {
|
||||
//waiting 1 second for gdbserver start
|
||||
@ -438,16 +437,16 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
}
|
||||
|
||||
let tool_path = match config.android_cross_path.to_str() {
|
||||
Some(x) => x.to_string(),
|
||||
Some(x) => x.to_owned(),
|
||||
None => fatal("cannot find android cross path")
|
||||
};
|
||||
|
||||
let debugger_script = make_out_name(config, testfile, "debugger.script");
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let debugger_opts =
|
||||
vec!("-quiet".to_string(),
|
||||
"-batch".to_string(),
|
||||
"-nx".to_string(),
|
||||
vec!("-quiet".to_owned(),
|
||||
"-batch".to_owned(),
|
||||
"-nx".to_owned(),
|
||||
format!("-command={}", debugger_script.to_str().unwrap()));
|
||||
|
||||
let mut gdb_path = tool_path;
|
||||
@ -460,7 +459,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
&gdb_path,
|
||||
None,
|
||||
&debugger_opts,
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
None)
|
||||
.expect(&format!("failed to exec `{:?}`", gdb_path));
|
||||
let cmdline = {
|
||||
@ -489,7 +488,7 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
.to_owned();
|
||||
// write debugger script
|
||||
let mut script_str = String::with_capacity(2048);
|
||||
script_str.push_str(&format!("set charset {}\n", charset()));
|
||||
@ -555,17 +554,17 @@ fn run_debuginfo_gdb_test(config: &Config, props: &TestProps, testfile: &Path) {
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let debugger_opts =
|
||||
vec!("-quiet".to_string(),
|
||||
"-batch".to_string(),
|
||||
"-nx".to_string(),
|
||||
vec!("-quiet".to_owned(),
|
||||
"-batch".to_owned(),
|
||||
"-nx".to_owned(),
|
||||
format!("-command={}", debugger_script.to_str().unwrap()));
|
||||
|
||||
let proc_args = ProcArgs {
|
||||
prog: debugger().to_string(),
|
||||
prog: debugger().to_owned(),
|
||||
args: debugger_opts,
|
||||
};
|
||||
|
||||
let environment = vec![("PYTHONPATH".to_string(), rust_pp_module_abs_path)];
|
||||
let environment = vec![("PYTHONPATH".to_owned(), rust_pp_module_abs_path)];
|
||||
|
||||
debugger_run_result = compose_and_run(config,
|
||||
testfile,
|
||||
@ -651,7 +650,7 @@ fn run_debuginfo_lldb_test(config: &Config, props: &TestProps, testfile: &Path)
|
||||
let rust_pp_module_abs_path = rust_src_root.join(rust_pp_module_rel_path)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string();
|
||||
.to_owned();
|
||||
|
||||
script_str.push_str(&format!("command script import {}\n",
|
||||
&rust_pp_module_abs_path[..])[..]);
|
||||
@ -791,9 +790,9 @@ fn cleanup_debug_info_options(options: &Option<String>) -> Option<String> {
|
||||
|
||||
// Remove options that are either unwanted (-O) or may lead to duplicates due to RUSTFLAGS.
|
||||
let options_to_remove = [
|
||||
"-O".to_string(),
|
||||
"-g".to_string(),
|
||||
"--debuginfo".to_string()
|
||||
"-O".to_owned(),
|
||||
"-g".to_owned(),
|
||||
"--debuginfo".to_owned()
|
||||
];
|
||||
let new_options =
|
||||
split_maybe_args(options).into_iter()
|
||||
@ -813,7 +812,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
|
||||
s
|
||||
.trim()
|
||||
.split("[...]")
|
||||
.map(|x| x.to_string())
|
||||
.map(str::to_owned)
|
||||
.collect()
|
||||
}).collect();
|
||||
// check if each line in props.check_lines appears in the
|
||||
@ -953,6 +952,9 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
|
||||
// filename:line1:col1: line2:col2: *warning:* msg
|
||||
// where line1:col1: is the starting point, line2:col2:
|
||||
// is the ending point, and * represents ANSI color codes.
|
||||
//
|
||||
// This pattern is ambiguous on windows, because filename may contain
|
||||
// a colon, so any path prefix must be detected and removed first.
|
||||
for line in proc_res.stderr.lines() {
|
||||
let mut was_expected = false;
|
||||
let mut prev = 0;
|
||||
@ -1007,7 +1009,16 @@ fn check_expected_errors(expected_errors: Vec<errors::ExpectedError>,
|
||||
}
|
||||
}
|
||||
|
||||
fn is_compiler_error_or_warning(line: &str) -> bool {
|
||||
fn is_compiler_error_or_warning(mut line: &str) -> bool {
|
||||
// Remove initial prefix which may contain a colon
|
||||
let mut components = Path::new(line).components();
|
||||
if let Some(Component::Prefix(_)) = components.peek() {
|
||||
components.next();
|
||||
}
|
||||
|
||||
// Safe as path was originally constructed from a &str ^
|
||||
line = components.as_path().to_str().unwrap();
|
||||
|
||||
let mut i = 0;
|
||||
return
|
||||
scan_until_char(line, ':', &mut i) &&
|
||||
@ -1128,8 +1139,8 @@ fn compile_test(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let link_args = vec!("-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
let link_args = vec!("-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned());
|
||||
let args = make_compile_args(config,
|
||||
props,
|
||||
link_args,
|
||||
@ -1143,14 +1154,14 @@ fn document(config: &Config, props: &TestProps,
|
||||
let out_dir = output_base_name(config, testfile);
|
||||
let _ = fs::remove_dir_all(&out_dir);
|
||||
ensure_dir(&out_dir);
|
||||
let mut args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string(),
|
||||
"-o".to_string(),
|
||||
out_dir.to_str().unwrap().to_string(),
|
||||
testfile.to_str().unwrap().to_string()];
|
||||
let mut args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned(),
|
||||
"-o".to_owned(),
|
||||
out_dir.to_str().unwrap().to_owned(),
|
||||
testfile.to_str().unwrap().to_owned()];
|
||||
args.extend(split_maybe_args(&props.compile_flags));
|
||||
let args = ProcArgs {
|
||||
prog: config.rustdoc_path.to_str().unwrap().to_string(),
|
||||
prog: config.rustdoc_path.to_str().unwrap().to_owned(),
|
||||
args: args,
|
||||
};
|
||||
(compose_and_run_compiler(config, props, testfile, args, None), out_dir)
|
||||
@ -1189,8 +1200,8 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
|
||||
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let extra_link_args = vec!["-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string()];
|
||||
let extra_link_args = vec!["-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned()];
|
||||
|
||||
for rel_ab in &props.aux_builds {
|
||||
let abs_ab = config.aux_base.join(rel_ab);
|
||||
@ -1208,9 +1219,9 @@ fn compose_and_run_compiler(config: &Config, props: &TestProps,
|
||||
// however, that if the library is built with `force_host` then it's
|
||||
// ok to be a dylib as the host should always support dylibs.
|
||||
if config.target.contains("musl") && !aux_props.force_host {
|
||||
vec!("--crate-type=lib".to_string())
|
||||
vec!("--crate-type=lib".to_owned())
|
||||
} else {
|
||||
vec!("--crate-type=dylib".to_string())
|
||||
vec!("--crate-type=dylib".to_owned())
|
||||
}
|
||||
};
|
||||
crate_type.extend(extra_link_args.clone());
|
||||
@ -1290,26 +1301,26 @@ fn make_compile_args<F>(config: &Config,
|
||||
&*config.target
|
||||
};
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut args = vec!(testfile.to_str().unwrap().to_string(),
|
||||
"-L".to_string(),
|
||||
config.build_base.to_str().unwrap().to_string(),
|
||||
let mut args = vec!(testfile.to_str().unwrap().to_owned(),
|
||||
"-L".to_owned(),
|
||||
config.build_base.to_str().unwrap().to_owned(),
|
||||
format!("--target={}", target));
|
||||
args.push_all(&extras);
|
||||
if !props.no_prefer_dynamic {
|
||||
args.push("-C".to_string());
|
||||
args.push("prefer-dynamic".to_string());
|
||||
args.push("-C".to_owned());
|
||||
args.push("prefer-dynamic".to_owned());
|
||||
}
|
||||
let path = match xform_file {
|
||||
TargetLocation::ThisFile(path) => {
|
||||
args.push("-o".to_string());
|
||||
args.push("-o".to_owned());
|
||||
path
|
||||
}
|
||||
TargetLocation::ThisDirectory(path) => {
|
||||
args.push("--out-dir".to_string());
|
||||
args.push("--out-dir".to_owned());
|
||||
path
|
||||
}
|
||||
};
|
||||
args.push(path.to_str().unwrap().to_string());
|
||||
args.push(path.to_str().unwrap().to_owned());
|
||||
if props.force_host {
|
||||
args.extend(split_maybe_args(&config.host_rustcflags));
|
||||
} else {
|
||||
@ -1317,7 +1328,7 @@ fn make_compile_args<F>(config: &Config,
|
||||
}
|
||||
args.extend(split_maybe_args(&props.compile_flags));
|
||||
return ProcArgs {
|
||||
prog: config.rustc_path.to_str().unwrap().to_string(),
|
||||
prog: config.rustc_path.to_str().unwrap().to_owned(),
|
||||
args: args,
|
||||
};
|
||||
}
|
||||
@ -1347,7 +1358,7 @@ fn make_run_args(config: &Config, props: &TestProps, testfile: &Path)
|
||||
let exe_file = make_exe_name(config, testfile);
|
||||
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
args.push(exe_file.to_str().unwrap().to_string());
|
||||
args.push(exe_file.to_str().unwrap().to_owned());
|
||||
|
||||
// Add the arguments in the run_flags directive
|
||||
args.extend(split_maybe_args(&props.run_flags));
|
||||
@ -1368,7 +1379,7 @@ fn split_maybe_args(argstr: &Option<String>) -> Vec<String> {
|
||||
if s.chars().all(|c| c.is_whitespace()) {
|
||||
None
|
||||
} else {
|
||||
Some(s.to_string())
|
||||
Some(s.to_owned())
|
||||
}
|
||||
}).collect()
|
||||
}
|
||||
@ -1503,7 +1514,7 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
// get bare program string
|
||||
let mut tvec: Vec<String> = args.prog
|
||||
.split('/')
|
||||
.map(|ts| ts.to_string())
|
||||
.map(str::to_owned)
|
||||
.collect();
|
||||
let prog_short = tvec.pop().unwrap();
|
||||
|
||||
@ -1512,12 +1523,12 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
&config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"push".to_string(),
|
||||
"push".to_owned(),
|
||||
args.prog.clone(),
|
||||
config.adb_test_dir.clone()
|
||||
],
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
if config.verbose {
|
||||
@ -1533,7 +1544,7 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
let mut runargs = Vec::new();
|
||||
|
||||
// run test via adb_run_wrapper
|
||||
runargs.push("shell".to_string());
|
||||
runargs.push("shell".to_owned());
|
||||
for (key, val) in env {
|
||||
runargs.push(format!("{}={}", key, val));
|
||||
}
|
||||
@ -1542,19 +1553,19 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
runargs.push(format!("{}", prog_short));
|
||||
|
||||
for tv in &args.args {
|
||||
runargs.push(tv.to_string());
|
||||
runargs.push(tv.to_owned());
|
||||
}
|
||||
procsrv::run("",
|
||||
&config.adb_path,
|
||||
None,
|
||||
&runargs,
|
||||
vec!(("".to_string(), "".to_string())), Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())), Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
// get exitcode of result
|
||||
runargs = Vec::new();
|
||||
runargs.push("shell".to_string());
|
||||
runargs.push("cat".to_string());
|
||||
runargs.push("shell".to_owned());
|
||||
runargs.push("cat".to_owned());
|
||||
runargs.push(format!("{}/{}.exitcode", config.adb_test_dir, prog_short));
|
||||
|
||||
let procsrv::Result{ out: exitcode_out, err: _, status: _ } =
|
||||
@ -1562,8 +1573,8 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
&config.adb_path,
|
||||
None,
|
||||
&runargs,
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
let mut exitcode: i32 = 0;
|
||||
@ -1577,8 +1588,8 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
|
||||
// get stdout of result
|
||||
runargs = Vec::new();
|
||||
runargs.push("shell".to_string());
|
||||
runargs.push("cat".to_string());
|
||||
runargs.push("shell".to_owned());
|
||||
runargs.push("cat".to_owned());
|
||||
runargs.push(format!("{}/{}.stdout", config.adb_test_dir, prog_short));
|
||||
|
||||
let procsrv::Result{ out: stdout_out, err: _, status: _ } =
|
||||
@ -1586,14 +1597,14 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
&config.adb_path,
|
||||
None,
|
||||
&runargs,
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
// get stderr of result
|
||||
runargs = Vec::new();
|
||||
runargs.push("shell".to_string());
|
||||
runargs.push("cat".to_string());
|
||||
runargs.push("shell".to_owned());
|
||||
runargs.push("cat".to_owned());
|
||||
runargs.push(format!("{}/{}.stderr", config.adb_test_dir, prog_short));
|
||||
|
||||
let procsrv::Result{ out: stderr_out, err: _, status: _ } =
|
||||
@ -1601,8 +1612,8 @@ fn _arm_exec_compiled_test(config: &Config,
|
||||
&config.adb_path,
|
||||
None,
|
||||
&runargs,
|
||||
vec!(("".to_string(), "".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(), "".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
dump_output(config,
|
||||
@ -1630,15 +1641,15 @@ fn _arm_push_aux_shared_library(config: &Config, testfile: &Path) {
|
||||
&config.adb_path,
|
||||
None,
|
||||
&[
|
||||
"push".to_string(),
|
||||
"push".to_owned(),
|
||||
file.to_str()
|
||||
.unwrap()
|
||||
.to_string(),
|
||||
config.adb_test_dir.to_string(),
|
||||
.to_owned(),
|
||||
config.adb_test_dir.to_owned(),
|
||||
],
|
||||
vec!(("".to_string(),
|
||||
"".to_string())),
|
||||
Some("".to_string()))
|
||||
vec!(("".to_owned(),
|
||||
"".to_owned())),
|
||||
Some("".to_owned()))
|
||||
.expect(&format!("failed to exec `{}`", config.adb_path));
|
||||
|
||||
if config.verbose {
|
||||
@ -1656,10 +1667,10 @@ fn compile_test_and_save_ir(config: &Config, props: &TestProps,
|
||||
testfile: &Path) -> ProcRes {
|
||||
let aux_dir = aux_output_dir_name(config, testfile);
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
let mut link_args = vec!("-L".to_string(),
|
||||
aux_dir.to_str().unwrap().to_string());
|
||||
let llvm_args = vec!("--emit=llvm-ir".to_string(),
|
||||
"--crate-type=lib".to_string());
|
||||
let mut link_args = vec!("-L".to_owned(),
|
||||
aux_dir.to_str().unwrap().to_owned());
|
||||
let llvm_args = vec!("--emit=llvm-ir".to_owned(),
|
||||
"--crate-type=lib".to_owned());
|
||||
link_args.extend(llvm_args);
|
||||
let args = make_compile_args(config,
|
||||
props,
|
||||
@ -1676,9 +1687,9 @@ fn check_ir_with_filecheck(config: &Config, testfile: &Path) -> ProcRes {
|
||||
let prog = config.llvm_bin_path.as_ref().unwrap().join("FileCheck");
|
||||
let proc_args = ProcArgs {
|
||||
// FIXME (#9639): This needs to handle non-utf8 paths
|
||||
prog: prog.to_str().unwrap().to_string(),
|
||||
prog: prog.to_str().unwrap().to_owned(),
|
||||
args: vec!(format!("-input-file={}", irfile.to_str().unwrap()),
|
||||
testfile.to_str().unwrap().to_string())
|
||||
testfile.to_str().unwrap().to_owned())
|
||||
};
|
||||
compose_and_run(config, testfile, proc_args, Vec::new(), "", None, None)
|
||||
}
|
||||
|
||||
@ -73,7 +73,7 @@ pub fn make_new_path(path: &str) -> String {
|
||||
Ok(curr) => {
|
||||
format!("{}{}{}", path, path_div(), curr)
|
||||
}
|
||||
Err(..) => path.to_string()
|
||||
Err(..) => path.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,11 +1,5 @@
|
||||
# Rust documentations
|
||||
|
||||
## Dependencies
|
||||
|
||||
[Pandoc](http://johnmacfarlane.net/pandoc/installing.html), a universal
|
||||
document converter, is required to generate docs as HTML from Rust's
|
||||
source code.
|
||||
|
||||
## Building
|
||||
|
||||
To generate all the docs, just run `make docs` from the root of the repository.
|
||||
@ -26,15 +20,12 @@ To generate an HTML version of a doc from Markdown manually, you can do
|
||||
something like:
|
||||
|
||||
~~~~
|
||||
pandoc --from=markdown --to=html5 --number-sections -o reference.html reference.md
|
||||
rustdoc reference.md
|
||||
~~~~
|
||||
|
||||
(`reference.md` being the Rust Reference Manual.)
|
||||
|
||||
The syntax for pandoc flavored markdown can be found at:
|
||||
An overview of how to use the `rustdoc` command is available [in the docs][1].
|
||||
Further details are available from the command line by with `rustdoc --help`.
|
||||
|
||||
- http://johnmacfarlane.net/pandoc/README.html#pandocs-markdown
|
||||
|
||||
A nice quick reference (for non-pandoc markdown) is at:
|
||||
|
||||
- http://kramdown.gettalong.org/quickref.html
|
||||
[1]: https://github.com/rust-lang/rust/blob/master/src/doc/trpl/documentation.md
|
||||
|
||||
@ -1 +1 @@
|
||||
<link rel="shortcut icon" href="http://www.rust-lang.org/favicon.ico">
|
||||
<link rel="shortcut icon" href="https://www.rust-lang.org/favicon.ico">
|
||||
|
||||
@ -281,7 +281,7 @@ type_path_tail : '<' type_expr [ ',' type_expr ] + '>'
|
||||
## Macros
|
||||
|
||||
```antlr
|
||||
expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';'
|
||||
expr_macro_rules : "macro_rules" '!' ident '(' macro_rule * ')' ';'
|
||||
| "macro_rules" '!' ident '{' macro_rule * '}' ;
|
||||
macro_rule : '(' matcher * ')' "=>" '(' transcriber * ')' ';' ;
|
||||
matcher : '(' matcher * ')' | '[' matcher * ']'
|
||||
@ -306,7 +306,7 @@ transcriber : '(' transcriber * ')' | '[' transcriber * ']'
|
||||
|
||||
```antlr
|
||||
item : vis ? mod_item | fn_item | type_item | struct_item | enum_item
|
||||
| const_item | static_item | trait_item | impl_item | extern_block ;
|
||||
| const_item | static_item | trait_item | impl_item | extern_block_item ;
|
||||
```
|
||||
|
||||
### Type Parameters
|
||||
@ -636,31 +636,31 @@ lambda_expr : '|' ident_list '|' expr ;
|
||||
### While loops
|
||||
|
||||
```antlr
|
||||
while_expr : [ lifetime ':' ] "while" no_struct_literal_expr '{' block '}' ;
|
||||
while_expr : [ lifetime ':' ] ? "while" no_struct_literal_expr '{' block '}' ;
|
||||
```
|
||||
|
||||
### Infinite loops
|
||||
|
||||
```antlr
|
||||
loop_expr : [ lifetime ':' ] "loop" '{' block '}';
|
||||
loop_expr : [ lifetime ':' ] ? "loop" '{' block '}';
|
||||
```
|
||||
|
||||
### Break expressions
|
||||
|
||||
```antlr
|
||||
break_expr : "break" [ lifetime ];
|
||||
break_expr : "break" [ lifetime ] ?;
|
||||
```
|
||||
|
||||
### Continue expressions
|
||||
|
||||
```antlr
|
||||
continue_expr : "continue" [ lifetime ];
|
||||
continue_expr : "continue" [ lifetime ] ?;
|
||||
```
|
||||
|
||||
### For expressions
|
||||
|
||||
```antlr
|
||||
for_expr : [ lifetime ':' ] "for" pat "in" no_struct_literal_expr '{' block '}' ;
|
||||
for_expr : [ lifetime ':' ] ? "for" pat "in" no_struct_literal_expr '{' block '}' ;
|
||||
```
|
||||
|
||||
### If expressions
|
||||
@ -688,13 +688,12 @@ match_pat : pat [ '|' pat ] * [ "if" expr ] ? ;
|
||||
```antlr
|
||||
if_let_expr : "if" "let" pat '=' expr '{' block '}'
|
||||
else_tail ? ;
|
||||
else_tail : "else" [ if_expr | if_let_expr | '{' block '}' ] ;
|
||||
```
|
||||
|
||||
### While let loops
|
||||
|
||||
```antlr
|
||||
while_let_expr : "while" "let" pat '=' expr '{' block '}' ;
|
||||
while_let_expr : [ lifetime ':' ] ? "while" "let" pat '=' expr '{' block '}' ;
|
||||
```
|
||||
|
||||
### Return expressions
|
||||
@ -754,8 +753,6 @@ return_expr : "return" expr ? ;
|
||||
```antlr
|
||||
closure_type := [ 'unsafe' ] [ '<' lifetime-list '>' ] '|' arg-list '|'
|
||||
[ ':' bound-list ] [ '->' type ]
|
||||
procedure_type := 'proc' [ '<' lifetime-list '>' ] '(' arg-list ')'
|
||||
[ ':' bound-list ] [ '->' type ]
|
||||
lifetime-list := lifetime | lifetime ',' lifetime-list
|
||||
arg-list := ident ':' type | ident ':' type ',' arg-list
|
||||
bound-list := bound | bound '+' bound-list
|
||||
|
||||
@ -20,13 +20,30 @@ series of small examples.
|
||||
|
||||
[rbe]: http://rustbyexample.com/
|
||||
|
||||
# The Standard Library
|
||||
# Language Reference
|
||||
|
||||
Rust does not have an exact specification yet, but an effort to describe as much of
|
||||
the language in as much detail as possible is in [the reference](reference.html).
|
||||
|
||||
# Standard Library Reference
|
||||
|
||||
We have [API documentation for the entire standard
|
||||
library](std/index.html). There's a list of crates on the left with more
|
||||
specific sections, or you can use the search bar at the top to search for
|
||||
something if you know its name.
|
||||
|
||||
# Tools
|
||||
|
||||
[Cargo](https://crates.io) is the Rust's package manager providing access to libraries
|
||||
beyond the standard one, and its website contains lots of good documentation.
|
||||
|
||||
[`rustdoc`](book/documentation.html) is the Rust's documentation generator, a tool converting
|
||||
annotated source code into HTML docs.
|
||||
|
||||
A bunch of non-official tools are available, such as [Racer](https://github.com/phildawes/racer)
|
||||
(code completion engine), or [rustfmt](https://github.com/nrc/rustfmt) (source code formatter),
|
||||
or text editor plugins.
|
||||
|
||||
# Community & Getting Help
|
||||
|
||||
If you need help with something, or just want to talk about Rust with others,
|
||||
@ -54,25 +71,10 @@ There is an active [subreddit](https://reddit.com/r/rust) with lots of
|
||||
discussion and news about Rust.
|
||||
|
||||
There is also a [user forum](https://users.rust-lang.org), for all
|
||||
user-oriented discussion, and a [developer
|
||||
user-oriented discussion, and a [developer
|
||||
forum](https://internals.rust-lang.org/), where the development of Rust
|
||||
itself is discussed.
|
||||
|
||||
# Specification
|
||||
|
||||
Rust does not have an exact specification, but an effort to describe as much of
|
||||
the language in as much detail as possible is in [the reference](reference.html).
|
||||
|
||||
# Tools
|
||||
|
||||
Rust is still a young language, so there isn't a ton of tooling yet, but the
|
||||
tools we have are really nice.
|
||||
|
||||
[Cargo](https://crates.io) is Rust's package manager, and its website contains
|
||||
lots of good documentation.
|
||||
|
||||
[`rustdoc`](book/documentation.html) is used to generate documentation for Rust code.
|
||||
|
||||
# FAQs
|
||||
|
||||
There are questions that are asked quite often, so we've made FAQs for them:
|
||||
@ -95,5 +97,4 @@ languages:
|
||||
- [Russian](https://github.com/kgv/rust_book_ru)
|
||||
- [Korean](https://github.com/rust-kr/doc.rust-kr.org)
|
||||
- [Chinese](https://github.com/KaiserY/rust-book-chinese)
|
||||
- [Spanish](https://github.com/goyox86/elpr)
|
||||
|
||||
- [Spanish](https://goyox86.github.io/elpr)
|
||||
|
||||
@ -127,7 +127,7 @@ fundamentally unsynchronized and compilers are free to aggressively optimize
|
||||
them. In particular, data accesses are free to be reordered by the compiler on
|
||||
the assumption that the program is single-threaded. The hardware is also free to
|
||||
propagate the changes made in data accesses to other threads as lazily and
|
||||
inconsistently as it wants. Mostly critically, data accesses are how data races
|
||||
inconsistently as it wants. Most critically, data accesses are how data races
|
||||
happen. Data accesses are very friendly to the hardware and compiler, but as
|
||||
we've seen they offer *awful* semantics to try to write synchronized code with.
|
||||
Actually, that's too weak.
|
||||
@ -210,18 +210,18 @@ use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::thread;
|
||||
|
||||
fn main() {
|
||||
let lock = Arc::new(AtomicBool::new(true)); // value answers "am I locked?"
|
||||
let lock = Arc::new(AtomicBool::new(false)); // value answers "am I locked?"
|
||||
|
||||
// ... distribute lock to threads somehow ...
|
||||
|
||||
// Try to acquire the lock by setting it to false
|
||||
while !lock.compare_and_swap(true, false, Ordering::Acquire) { }
|
||||
// Try to acquire the lock by setting it to true
|
||||
while lock.compare_and_swap(false, true, Ordering::Acquire) { }
|
||||
// broke out of the loop, so we successfully acquired the lock!
|
||||
|
||||
// ... scary data accesses ...
|
||||
|
||||
// ok we're done, release the lock
|
||||
lock.store(true, Ordering::Release);
|
||||
lock.store(false, Ordering::Release);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -22,7 +22,7 @@ Coercion is allowed between the following types:
|
||||
for all pointer types (including smart pointers like Box and Rc). Unsize is
|
||||
only implemented automatically, and enables the following transformations:
|
||||
|
||||
* `[T, ..n]` => `[T]`
|
||||
* `[T; n]` => `[T]`
|
||||
* `T` => `Trait` where `T: Trait`
|
||||
* `Foo<..., T, ...>` => `Foo<..., U, ...>` where:
|
||||
* `T: Unsize<U>`
|
||||
|
||||
@ -7,7 +7,7 @@ an abstraction over them in a relatively uncontroversial way. Message passing,
|
||||
green threads, and async APIs are all diverse enough that any abstraction over
|
||||
them tends to involve trade-offs that we weren't willing to commit to for 1.0.
|
||||
|
||||
However the way Rust models concurrency makes it relatively easy design your own
|
||||
However the way Rust models concurrency makes it relatively easy to design your own
|
||||
concurrency paradigm as a library and have everyone else's code Just Work
|
||||
with yours. Just require the right lifetimes and Send and Sync where appropriate
|
||||
and you're off to the races. Or rather, off to the... not... having... races.
|
||||
|
||||
@ -26,13 +26,16 @@ this is totally fine.
|
||||
For instance, a custom implementation of `Box` might write `Drop` like this:
|
||||
|
||||
```rust
|
||||
#![feature(heap_api, core_intrinsics, unique)]
|
||||
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use std::rt::heap;
|
||||
use std::ptr::Unique;
|
||||
use std::intrinsics::drop_in_place;
|
||||
use std::mem;
|
||||
|
||||
use alloc::heap;
|
||||
|
||||
struct Box<T>{ ptr: Unique<T> }
|
||||
|
||||
impl<T> Drop for Box<T> {
|
||||
@ -45,22 +48,26 @@ impl<T> Drop for Box<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
and this works fine because when Rust goes to drop the `ptr` field it just sees
|
||||
a [Unique][] that has no actual `Drop` implementation. Similarly nothing can
|
||||
a [Unique] that has no actual `Drop` implementation. Similarly nothing can
|
||||
use-after-free the `ptr` because when drop exits, it becomes inacessible.
|
||||
|
||||
However this wouldn't work:
|
||||
|
||||
```rust
|
||||
#![feature(heap_api, core_intrinsics, unique)]
|
||||
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use std::rt::heap;
|
||||
use std::ptr::Unique;
|
||||
use std::intrinsics::drop_in_place;
|
||||
use std::mem;
|
||||
|
||||
use alloc::heap;
|
||||
|
||||
struct Box<T>{ ptr: Unique<T> }
|
||||
|
||||
impl<T> Drop for Box<T> {
|
||||
@ -87,6 +94,7 @@ impl<T> Drop for SuperBox<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
After we deallocate the `box`'s ptr in SuperBox's destructor, Rust will
|
||||
@ -120,7 +128,7 @@ enum Link {
|
||||
will have its inner Box field dropped if and only if an instance stores the
|
||||
Next variant.
|
||||
|
||||
In general this works really nice because you don't need to worry about
|
||||
In general this works really nicely because you don't need to worry about
|
||||
adding/removing drops when you refactor your data layout. Still there's
|
||||
certainly many valid usecases for needing to do trickier things with
|
||||
destructors.
|
||||
@ -129,13 +137,16 @@ The classic safe solution to overriding recursive drop and allowing moving out
|
||||
of Self during `drop` is to use an Option:
|
||||
|
||||
```rust
|
||||
#![feature(heap_api, core_intrinsics, unique)]
|
||||
#![feature(alloc, heap_api, core_intrinsics, unique)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use std::rt::heap;
|
||||
use std::ptr::Unique;
|
||||
use std::intrinsics::drop_in_place;
|
||||
use std::mem;
|
||||
|
||||
use alloc::heap;
|
||||
|
||||
struct Box<T>{ ptr: Unique<T> }
|
||||
|
||||
impl<T> Drop for Box<T> {
|
||||
@ -165,6 +176,7 @@ impl<T> Drop for SuperBox<T> {
|
||||
}
|
||||
}
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
However this has fairly odd semantics: you're saying that a field that *should*
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
% Drop Flags
|
||||
|
||||
The examples in the previous section introduce an interesting problem for Rust.
|
||||
We have seen that's possible to conditionally initialize, deinitialize, and
|
||||
We have seen that it's possible to conditionally initialize, deinitialize, and
|
||||
reinitialize locations of memory totally safely. For Copy types, this isn't
|
||||
particularly notable since they're just a random pile of bits. However types
|
||||
with destructors are a different story: Rust needs to know whether to call a
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
% Drop Check
|
||||
|
||||
We have seen how lifetimes provide us some fairly simple rules for ensuring
|
||||
that never read dangling references. However up to this point we have only ever
|
||||
that we never read dangling references. However up to this point we have only ever
|
||||
interacted with the *outlives* relationship in an inclusive manner. That is,
|
||||
when we talked about `'a: 'b`, it was ok for `'a` to live *exactly* as long as
|
||||
`'b`. At first glance, this seems to be a meaningless distinction. Nothing ever
|
||||
|
||||
@ -85,8 +85,8 @@ support values.
|
||||
Safe code need not worry about ZSTs, but *unsafe* code must be careful about the
|
||||
consequence of types with no size. In particular, pointer offsets are no-ops,
|
||||
and standard allocators (including jemalloc, the one used by default in Rust)
|
||||
generally consider passing in `0` for the size of an allocation as Undefined
|
||||
Behaviour.
|
||||
may return `nullptr` when a zero-sized allocation is requested, which is
|
||||
indistinguishable from out of memory.
|
||||
|
||||
|
||||
|
||||
|
||||
@ -155,7 +155,6 @@ impl<T> Rc<T> {
|
||||
impl<T> Drop for Rc<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let inner = &mut ;
|
||||
(*self.ptr).ref_count -= 1;
|
||||
if (*self.ptr).ref_count == 0 {
|
||||
// drop the data and then free it
|
||||
|
||||
@ -52,7 +52,7 @@ likely desugar to the following:
|
||||
}
|
||||
```
|
||||
|
||||
Wow. That’s... awful. Let’s all take a moment to thank Rust for making this easier.
|
||||
Wow. That's... awful. Let's all take a moment to thank Rust for making this easier.
|
||||
|
||||
Actually passing references to outer scopes will cause Rust to infer
|
||||
a larger lifetime:
|
||||
|
||||
@ -60,8 +60,8 @@ Unlike C, Undefined Behaviour is pretty limited in scope in Rust. All the core
|
||||
language cares about is preventing the following things:
|
||||
|
||||
* Dereferencing null or dangling pointers
|
||||
* Reading [uninitialized memory][]
|
||||
* Breaking the [pointer aliasing rules][]
|
||||
* Reading [uninitialized memory]
|
||||
* Breaking the [pointer aliasing rules]
|
||||
* Producing invalid primitive values:
|
||||
* dangling/null references
|
||||
* a `bool` that isn't 0 or 1
|
||||
|
||||
@ -26,7 +26,7 @@ still consumes a byte of space.
|
||||
* DSTs, tuples, and tagged unions are not a concept in C and as such are never
|
||||
FFI safe.
|
||||
|
||||
* **If the type would have any [drop flags][], they will still be added**
|
||||
* **If the type would have any [drop flags], they will still be added**
|
||||
|
||||
* This is equivalent to one of `repr(u*)` (see the next section) for enums. The
|
||||
chosen size is the default enum size for the target platform's C ABI. Note that
|
||||
|
||||
@ -36,9 +36,9 @@ struct A {
|
||||
}
|
||||
```
|
||||
|
||||
will be 32-bit aligned assuming these primitives are aligned to their size.
|
||||
It will therefore have a size that is a multiple of 32-bits. It will potentially
|
||||
*really* become:
|
||||
will be 32-bit aligned on an architecture that aligns these primitives to their
|
||||
respective sizes. The whole struct will therefore have a size that is a multiple
|
||||
of 32-bits. It will potentially become:
|
||||
|
||||
```rust
|
||||
struct A {
|
||||
@ -50,10 +50,10 @@ struct A {
|
||||
}
|
||||
```
|
||||
|
||||
There is *no indirection* for these types; all data is stored contiguously as
|
||||
you would expect in C. However with the exception of arrays (which are densely
|
||||
packed and in-order), the layout of data is not by default specified in Rust.
|
||||
Given the two following struct definitions:
|
||||
There is *no indirection* for these types; all data is stored within the struct,
|
||||
as you would expect in C. However with the exception of arrays (which are
|
||||
densely packed and in-order), the layout of data is not by default specified in
|
||||
Rust. Given the two following struct definitions:
|
||||
|
||||
```rust
|
||||
struct A {
|
||||
@ -62,18 +62,17 @@ struct A {
|
||||
}
|
||||
|
||||
struct B {
|
||||
x: i32,
|
||||
a: i32,
|
||||
b: u64,
|
||||
}
|
||||
```
|
||||
|
||||
Rust *does* guarantee that two instances of A have their data laid out in
|
||||
exactly the same way. However Rust *does not* guarantee that an instance of A
|
||||
has the same field ordering or padding as an instance of B (in practice there's
|
||||
no particular reason why they wouldn't, other than that its not currently
|
||||
guaranteed).
|
||||
exactly the same way. However Rust *does not* currently guarantee that an
|
||||
instance of A has the same field ordering or padding as an instance of B, though
|
||||
in practice there's no reason why they wouldn't.
|
||||
|
||||
With A and B as written, this is basically nonsensical, but several other
|
||||
With A and B as written, this point would seem to be pedantic, but several other
|
||||
features of Rust make it desirable for the language to play with data layout in
|
||||
complex ways.
|
||||
|
||||
@ -133,18 +132,21 @@ struct FooRepr {
|
||||
}
|
||||
```
|
||||
|
||||
And indeed this is approximately how it would be laid out in general
|
||||
(modulo the size and position of `tag`). However there are several cases where
|
||||
such a representation is inefficient. The classic case of this is Rust's
|
||||
"null pointer optimization". Given a pointer that is known to not be null
|
||||
(e.g. `&u32`), an enum can *store* a discriminant bit *inside* the pointer
|
||||
by using null as a special value. The net result is that
|
||||
`size_of::<Option<&T>>() == size_of::<&T>()`
|
||||
And indeed this is approximately how it would be laid out in general (modulo the
|
||||
size and position of `tag`).
|
||||
|
||||
There are many types in Rust that are, or contain, "not null" pointers such as
|
||||
However there are several cases where such a representation is inefficient. The
|
||||
classic case of this is Rust's "null pointer optimization": an enum consisting
|
||||
of a single outer unit variant (e.g. `None`) and a (potentially nested) non-
|
||||
nullable pointer variant (e.g. `&T`) makes the tag unnecessary, because a null
|
||||
pointer value can safely be interpreted to mean that the unit variant is chosen
|
||||
instead. The net result is that, for example, `size_of::<Option<&T>>() ==
|
||||
size_of::<&T>()`.
|
||||
|
||||
There are many types in Rust that are, or contain, non-nullable pointers such as
|
||||
`Box<T>`, `Vec<T>`, `String`, `&T`, and `&mut T`. Similarly, one can imagine
|
||||
nested enums pooling their tags into a single discriminant, as they are by
|
||||
definition known to have a limited range of valid values. In principle enums can
|
||||
definition known to have a limited range of valid values. In principle enums could
|
||||
use fairly elaborate algorithms to cache bits throughout nested types with
|
||||
special constrained representations. As such it is *especially* desirable that
|
||||
we leave enum layout unspecified today.
|
||||
|
||||
@ -35,7 +35,7 @@ unchecked contracts:
|
||||
|
||||
There is also `#[unsafe_no_drop_flag]`, which is a special case that exists for
|
||||
historical reasons and is in the process of being phased out. See the section on
|
||||
[drop flags][] for details.
|
||||
[drop flags] for details.
|
||||
|
||||
Some examples of unsafe functions:
|
||||
|
||||
@ -44,7 +44,7 @@ Some examples of unsafe functions:
|
||||
* `ptr::offset` is an intrinsic that invokes Undefined Behaviour if it is
|
||||
not "in bounds" as defined by LLVM.
|
||||
* `mem::transmute` reinterprets some value as having the given type,
|
||||
bypassing type safety in arbitrary ways. (see [conversions][] for details)
|
||||
bypassing type safety in arbitrary ways. (see [conversions] for details)
|
||||
* All FFI functions are `unsafe` because they can do arbitrary things.
|
||||
C being an obvious culprit, but generally any language can do something
|
||||
that Rust isn't happy about.
|
||||
@ -125,7 +125,7 @@ unsafe impl UnsafeOrd for MyType {
|
||||
But it's probably not the implementation you want.
|
||||
|
||||
Rust has traditionally avoided making traits unsafe because it makes Unsafe
|
||||
pervasive, which is not desirable. Send and Sync are unsafe is because thread
|
||||
pervasive, which is not desirable. The reason Send and Sync are unsafe is because thread
|
||||
safety is a *fundamental property* that unsafe code cannot possibly hope to defend
|
||||
against in the same way it would defend against a bad Ord implementation. The
|
||||
only way to possibly defend against thread-unsafety would be to *not use
|
||||
|
||||
@ -3,15 +3,15 @@
|
||||
Not everything obeys inherited mutability, though. Some types allow you to
|
||||
multiply alias a location in memory while mutating it. Unless these types use
|
||||
synchronization to manage this access, they are absolutely not thread safe. Rust
|
||||
captures this with through the `Send` and `Sync` traits.
|
||||
captures this through the `Send` and `Sync` traits.
|
||||
|
||||
* A type is Send if it is safe to send it to another thread.
|
||||
* A type is Sync if it is safe to share between threads (`&T` is Send).
|
||||
|
||||
Send and Sync are fundamental to Rust's concurrency story. As such, a
|
||||
substantial amount of special tooling exists to make them work right. First and
|
||||
foremost, they're [unsafe traits][]. This means that they are unsafe to
|
||||
implement, and other unsafe code can that they are correctly
|
||||
foremost, they're [unsafe traits]. This means that they are unsafe to
|
||||
implement, and other unsafe code can assume that they are correctly
|
||||
implemented. Since they're *marker traits* (they have no associated items like
|
||||
methods), correctly implemented simply means that they have the intrinsic
|
||||
properties an implementor should have. Incorrectly implementing Send or Sync can
|
||||
|
||||
@ -93,8 +93,8 @@ fn main() {
|
||||
|
||||
The signature of `overwrite` is clearly valid: it takes mutable references to
|
||||
two values of the same type, and overwrites one with the other. If `&mut T` was
|
||||
variant over T, then `&mut &'a str` would be a subtype of `&mut &'static str`,
|
||||
since `&'a str` is a subtype of `&'static str`. Therefore the lifetime of
|
||||
variant over T, then `&mut &'static str` would be a subtype of `&mut &'a str`,
|
||||
since `&'static str` is a subtype of `&'a str`. Therefore the lifetime of
|
||||
`forever_str` would successfully be "shrunk" down to the shorter lifetime of
|
||||
`string`, and `overwrite` would be called successfully. `string` would
|
||||
subsequently be dropped, and `forever_str` would point to freed memory when we
|
||||
|
||||
@ -21,7 +21,7 @@ same size. The ways to cause Undefined Behaviour with this are mind boggling.
|
||||
* No you can't do it
|
||||
* No you're not special
|
||||
* Transmuting to a reference without an explicitly provided lifetime
|
||||
produces an [unbounded lifetime][]
|
||||
produces an [unbounded lifetime]
|
||||
|
||||
`mem::transmute_copy<T, U>` somehow manages to be *even more* wildly unsafe than
|
||||
this. It copies `size_of<U>` bytes out of an `&T` and interprets them as a `U`.
|
||||
|
||||
@ -77,7 +77,7 @@ contain any `Drop` types.
|
||||
However when working with uninitialized memory you need to be ever-vigilant for
|
||||
Rust trying to drop values you make like this before they're fully initialized.
|
||||
Every control path through that variable's scope must initialize the value
|
||||
before it ends, if has a destructor.
|
||||
before it ends, if it has a destructor.
|
||||
*[This includes code panicking](unwinding.html)*.
|
||||
|
||||
And that's about it for working with uninitialized memory! Basically nothing
|
||||
|
||||
@ -9,7 +9,7 @@ This is perfectly fine because we already have `cap == 0` as our sentinel for no
|
||||
allocation. We don't even need to handle it specially in almost any code because
|
||||
we usually need to check if `cap > len` or `len > 0` anyway. The traditional
|
||||
Rust value to put here is `0x01`. The standard library actually exposes this
|
||||
as `std::rt::heap::EMPTY`. There are quite a few places where we'll
|
||||
as `alloc::heap::EMPTY`. There are quite a few places where we'll
|
||||
want to use `heap::EMPTY` because there's no real allocation to talk about but
|
||||
`null` would make the compiler do bad things.
|
||||
|
||||
@ -20,11 +20,12 @@ the `heap` API anyway, so let's just get that dependency over with.
|
||||
So:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(heap_api)]
|
||||
#![feature(alloc, heap_api)]
|
||||
|
||||
use std::rt::heap::EMPTY;
|
||||
use std::mem;
|
||||
|
||||
use alloc::heap::EMPTY;
|
||||
|
||||
impl<T> Vec<T> {
|
||||
fn new() -> Self {
|
||||
assert!(mem::size_of::<T>() != 0, "We're not ready to handle ZSTs");
|
||||
|
||||
@ -129,14 +129,16 @@ impl<'a, T> Drop for Drain<'a, T> {
|
||||
|
||||
impl<T> Vec<T> {
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
// this is a mem::forget safety thing. If Drain is forgotten, we just
|
||||
// leak the whole Vec's contents. Also we need to do this eventually
|
||||
// anyway, so why not do it now?
|
||||
self.len = 0;
|
||||
|
||||
unsafe {
|
||||
let iter = RawValIter::new(&self);
|
||||
|
||||
// this is a mem::forget safety thing. If Drain is forgotten, we just
|
||||
// leak the whole Vec's contents. Also we need to do this *eventually*
|
||||
// anyway, so why not do it now?
|
||||
self.len = 0;
|
||||
|
||||
Drain {
|
||||
iter: RawValIter::new(&self),
|
||||
iter: iter,
|
||||
vec: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,17 +2,16 @@
|
||||
|
||||
```rust
|
||||
#![feature(unique)]
|
||||
#![feature(heap_api)]
|
||||
#![feature(alloc, heap_api)]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
use std::ptr::{Unique, self};
|
||||
use std::rt::heap;
|
||||
use std::mem;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
use std::marker::PhantomData;
|
||||
|
||||
|
||||
|
||||
|
||||
use alloc::heap;
|
||||
|
||||
struct RawVec<T> {
|
||||
ptr: Unique<T>,
|
||||
@ -155,13 +154,16 @@ impl<T> Vec<T> {
|
||||
}
|
||||
|
||||
pub fn drain(&mut self) -> Drain<T> {
|
||||
// this is a mem::forget safety thing. If this is forgotten, we just
|
||||
// leak the whole Vec's contents. Also we need to do this *eventually*
|
||||
// anyway, so why not do it now?
|
||||
self.len = 0;
|
||||
unsafe {
|
||||
let iter = RawValIter::new(&self);
|
||||
|
||||
// this is a mem::forget safety thing. If Drain is forgotten, we just
|
||||
// leak the whole Vec's contents. Also we need to do this *eventually*
|
||||
// anyway, so why not do it now?
|
||||
self.len = 0;
|
||||
|
||||
Drain {
|
||||
iter: RawValIter::new(&self),
|
||||
iter: iter,
|
||||
vec: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@ -21,12 +21,12 @@ Some things that might be helpful to you though:
|
||||
|
||||
# Reference
|
||||
|
||||
* [The Rust official site](http://rust-lang.org)
|
||||
* [The Rust reference](http://doc.rust-lang.org/reference.html)
|
||||
* [The Rust official site](https://www.rust-lang.org)
|
||||
* [The Rust reference](https://doc.rust-lang.org/reference.html)
|
||||
|
||||
# Docs
|
||||
|
||||
* [The standard library](http://doc.rust-lang.org/std/)
|
||||
* [The standard library](https://doc.rust-lang.org/std/)
|
||||
|
||||
<script>
|
||||
function get_url_fragments() {
|
||||
@ -58,7 +58,7 @@ function populate_rust_search() {
|
||||
// #18540, use a single token
|
||||
|
||||
var a = document.createElement("a");
|
||||
a.href = "http://doc.rust-lang.org/core/?search=" + encodeURIComponent(lt);
|
||||
a.href = "https://doc.rust-lang.org/core/?search=" + encodeURIComponent(lt);
|
||||
a.textContent = lt;
|
||||
var search = document.getElementById('core-search');
|
||||
search.innerHTML = "";
|
||||
|
||||
@ -538,8 +538,9 @@ balanced, but they are otherwise not special.
|
||||
In the matcher, `$` _name_ `:` _designator_ matches the nonterminal in the Rust
|
||||
syntax named by _designator_. Valid designators are `item`, `block`, `stmt`,
|
||||
`pat`, `expr`, `ty` (type), `ident`, `path`, `tt` (either side of the `=>`
|
||||
in macro rules). In the transcriber, the designator is already known, and so
|
||||
only the name of a matched nonterminal comes after the dollar sign.
|
||||
in macro rules), and `meta` (contents of an attribute). In the transcriber, the
|
||||
designator is already known, and so only the name of a matched nonterminal comes
|
||||
after the dollar sign.
|
||||
|
||||
In both the matcher and transcriber, the Kleene star-like operator indicates
|
||||
repetition. The Kleene star operator consists of `$` and parentheses, optionally
|
||||
@ -1094,12 +1095,12 @@ typecheck:
|
||||
# fn my_err(s: &str) -> ! { panic!() }
|
||||
|
||||
fn f(i: i32) -> i32 {
|
||||
if i == 42 {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
my_err("Bad number!");
|
||||
}
|
||||
if i == 42 {
|
||||
return 42;
|
||||
}
|
||||
else {
|
||||
my_err("Bad number!");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -1398,9 +1399,9 @@ functions](#generic-functions).
|
||||
|
||||
```
|
||||
trait Seq<T> {
|
||||
fn len(&self) -> u32;
|
||||
fn elt_at(&self, n: u32) -> T;
|
||||
fn iter<F>(&self, F) where F: Fn(T);
|
||||
fn len(&self) -> u32;
|
||||
fn elt_at(&self, n: u32) -> T;
|
||||
fn iter<F>(&self, F) where F: Fn(T);
|
||||
}
|
||||
```
|
||||
|
||||
@ -1451,7 +1452,7 @@ fn draw_twice<T: Shape>(surface: Surface, sh: T) {
|
||||
}
|
||||
```
|
||||
|
||||
Traits also define an [trait object](#trait-objects) with the same
|
||||
Traits also define a [trait object](#trait-objects) with the same
|
||||
name as the trait. Values of this type are created by coercing from a
|
||||
pointer of some specific type to a pointer of trait type. For example,
|
||||
`&T` could be coerced to `&Shape` if `T: Shape` holds (and similarly
|
||||
@ -1488,19 +1489,41 @@ impl Num for f64 {
|
||||
let x: f64 = Num::from_i32(42);
|
||||
```
|
||||
|
||||
Traits may inherit from other traits. For example, in
|
||||
Traits may inherit from other traits. Consider the following example:
|
||||
|
||||
```
|
||||
trait Shape { fn area(&self) -> f64; }
|
||||
trait Circle : Shape { fn radius(&self) -> f64; }
|
||||
```
|
||||
|
||||
the syntax `Circle : Shape` means that types that implement `Circle` must also
|
||||
The syntax `Circle : Shape` means that types that implement `Circle` must also
|
||||
have an implementation for `Shape`. Multiple supertraits are separated by `+`,
|
||||
`trait Circle : Shape + PartialEq { }`. In an implementation of `Circle` for a
|
||||
given type `T`, methods can refer to `Shape` methods, since the typechecker
|
||||
checks that any type with an implementation of `Circle` also has an
|
||||
implementation of `Shape`.
|
||||
implementation of `Shape`:
|
||||
|
||||
```rust
|
||||
struct Foo;
|
||||
|
||||
trait Shape { fn area(&self) -> f64; }
|
||||
trait Circle : Shape { fn radius(&self) -> f64; }
|
||||
# impl Shape for Foo {
|
||||
# fn area(&self) -> f64 {
|
||||
# 0.0
|
||||
# }
|
||||
# }
|
||||
impl Circle for Foo {
|
||||
fn radius(&self) -> f64 {
|
||||
println!("calling area: {}", self.area());
|
||||
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
let c = Foo;
|
||||
c.radius();
|
||||
```
|
||||
|
||||
In type-parameterized functions, methods of the supertrait may be called on
|
||||
values of subtrait-bound type parameters. Referring to the previous example of
|
||||
@ -1556,8 +1579,12 @@ impl Shape for Circle {
|
||||
fn draw(&self, s: Surface) { do_draw_circle(s, *self); }
|
||||
fn bounding_box(&self) -> BoundingBox {
|
||||
let r = self.radius;
|
||||
BoundingBox{x: self.center.x - r, y: self.center.y - r,
|
||||
width: 2.0 * r, height: 2.0 * r}
|
||||
BoundingBox {
|
||||
x: self.center.x - r,
|
||||
y: self.center.y - r,
|
||||
width: 2.0 * r,
|
||||
height: 2.0 * r,
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -1592,10 +1619,10 @@ are written after the `impl` keyword.
|
||||
```
|
||||
# trait Seq<T> { fn dummy(&self, _: T) { } }
|
||||
impl<T> Seq<T> for Vec<T> {
|
||||
/* ... */
|
||||
/* ... */
|
||||
}
|
||||
impl Seq<bool> for u32 {
|
||||
/* Treat the integer as a sequence of bits */
|
||||
/* Treat the integer as a sequence of bits */
|
||||
}
|
||||
```
|
||||
|
||||
@ -1827,13 +1854,13 @@ An example of attributes:
|
||||
// A function marked as a unit test
|
||||
#[test]
|
||||
fn test_foo() {
|
||||
/* ... */
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// A conditionally-compiled module
|
||||
#[cfg(target_os="linux")]
|
||||
mod bar {
|
||||
/* ... */
|
||||
/* ... */
|
||||
}
|
||||
|
||||
// A lint attribute used to suppress a warning/error
|
||||
@ -1858,11 +1885,15 @@ type int8_t = i8;
|
||||
- `no_start` - disable linking to the `native` crate, which specifies the
|
||||
"start" language item.
|
||||
- `no_std` - disable linking to the `std` crate.
|
||||
- `plugin` — load a list of named crates as compiler plugins, e.g.
|
||||
- `plugin` - load a list of named crates as compiler plugins, e.g.
|
||||
`#![plugin(foo, bar)]`. Optional arguments for each plugin,
|
||||
i.e. `#![plugin(foo(... args ...))]`, are provided to the plugin's
|
||||
registrar function. The `plugin` feature gate is required to use
|
||||
this attribute.
|
||||
- `recursion_limit` - Sets the maximum depth for potentially
|
||||
infinitely-recursive compile-time operations like
|
||||
auto-dereference or macro expansion. The default is
|
||||
`#![recursion_limit="64"]`.
|
||||
|
||||
### Module-only attributes
|
||||
|
||||
@ -1901,10 +1932,16 @@ On an `extern` block, the following attributes are interpreted:
|
||||
name and type. This is feature gated and the exact behavior is
|
||||
implementation-defined (due to variety of linker invocation syntax).
|
||||
- `link` - indicate that a native library should be linked to for the
|
||||
declarations in this block to be linked correctly. `link` supports an optional `kind`
|
||||
key with three possible values: `dylib`, `static`, and `framework`. See [external blocks](#external-blocks) for more about external blocks. Two
|
||||
declarations in this block to be linked correctly. `link` supports an optional
|
||||
`kind` key with three possible values: `dylib`, `static`, and `framework`. See
|
||||
[external blocks](#external-blocks) for more about external blocks. Two
|
||||
examples: `#[link(name = "readline")]` and
|
||||
`#[link(name = "CoreFoundation", kind = "framework")]`.
|
||||
- `linked_from` - indicates what native library this block of FFI items is
|
||||
coming from. This attribute is of the form `#[linked_from = "foo"]` where
|
||||
`foo` is the name of a library in either `#[link]` or a `-l` flag. This
|
||||
attribute is currently required to export symbols from a Rust dynamic library
|
||||
on Windows, and it is feature gated behind the `linked_from` feature.
|
||||
|
||||
On declarations inside an `extern` block, the following attributes are
|
||||
interpreted:
|
||||
@ -2022,25 +2059,31 @@ arbitrarily complex configurations through nesting.
|
||||
|
||||
The following configurations must be defined by the implementation:
|
||||
|
||||
* `debug_assertions`. Enabled by default when compiling without optimizations.
|
||||
* `debug_assertions` - Enabled by default when compiling without optimizations.
|
||||
This can be used to enable extra debugging code in development but not in
|
||||
production. For example, it controls the behavior of the standard library's
|
||||
`debug_assert!` macro.
|
||||
* `target_arch = "..."`. Target CPU architecture, such as `"x86"`, `"x86_64"`
|
||||
* `target_arch = "..."` - Target CPU architecture, such as `"x86"`, `"x86_64"`
|
||||
`"mips"`, `"powerpc"`, `"arm"`, or `"aarch64"`.
|
||||
* `target_endian = "..."`. Endianness of the target CPU, either `"little"` or
|
||||
* `target_endian = "..."` - Endianness of the target CPU, either `"little"` or
|
||||
`"big"`.
|
||||
* `target_family = "..."`. Operating system family of the target, e. g.
|
||||
* `target_env = ".."` - An option provided by the compiler by default
|
||||
describing the runtime environment of the target platform. Some examples of
|
||||
this are `musl` for builds targeting the MUSL libc implementation, `msvc` for
|
||||
Windows builds targeting MSVC, and `gnu` frequently the rest of the time. This
|
||||
option may also be blank on some platforms.
|
||||
* `target_family = "..."` - Operating system family of the target, e. g.
|
||||
`"unix"` or `"windows"`. The value of this configuration option is defined
|
||||
as a configuration itself, like `unix` or `windows`.
|
||||
* `target_os = "..."`. Operating system of the target, examples include
|
||||
* `target_os = "..."` - Operating system of the target, examples include
|
||||
`"windows"`, `"macos"`, `"ios"`, `"linux"`, `"android"`, `"freebsd"`, `"dragonfly"`,
|
||||
`"bitrig"` , `"openbsd"` or `"netbsd"`.
|
||||
* `target_pointer_width = "..."`. Target pointer width in bits. This is set
|
||||
* `target_pointer_width = "..."` - Target pointer width in bits. This is set
|
||||
to `"32"` for targets with 32-bit pointers, and likewise set to `"64"` for
|
||||
64-bit pointers.
|
||||
* `unix`. See `target_family`.
|
||||
* `windows`. See `target_family`.
|
||||
* `test` - Enabled when compiling the test harness (using the `--test` flag).
|
||||
* `unix` - See `target_family`.
|
||||
* `windows` - See `target_family`.
|
||||
|
||||
You can also set another attribute based on a `cfg` variable with `cfg_attr`:
|
||||
|
||||
@ -2324,9 +2367,6 @@ The currently implemented features of the reference compiler are:
|
||||
into a Rust program. This capability, especially the signature for the
|
||||
annotated function, is subject to change.
|
||||
|
||||
* `struct_inherit` - Allows using struct inheritance, which is barely
|
||||
implemented and will probably be removed. Don't use this.
|
||||
|
||||
* `struct_variant` - Structural enum variants (those with named fields). It is
|
||||
currently unknown whether this style of enum variant is as
|
||||
fully supported as the tuple-forms, and it's not certain
|
||||
@ -2860,9 +2900,9 @@ An example of an `as` expression:
|
||||
# fn len(values: &[f64]) -> i32 { 0 }
|
||||
|
||||
fn average(values: &[f64]) -> f64 {
|
||||
let sum: f64 = sum(values);
|
||||
let size: f64 = len(values) as f64;
|
||||
sum / size
|
||||
let sum: f64 = sum(values);
|
||||
let size: f64 = len(values) as f64;
|
||||
sum / size
|
||||
}
|
||||
```
|
||||
|
||||
@ -3161,16 +3201,6 @@ let z = match x { &0 => "zero", _ => "some" };
|
||||
assert_eq!(y, z);
|
||||
```
|
||||
|
||||
A pattern that's just an identifier, like `Nil` in the previous example, could
|
||||
either refer to an enum variant that's in scope, or bind a new variable. The
|
||||
compiler resolves this ambiguity by forbidding variable bindings that occur in
|
||||
`match` patterns from shadowing names of variants that are in scope. For
|
||||
example, wherever `List` is in scope, a `match` pattern would not be able to
|
||||
bind `Nil` as a new name. The compiler interprets a variable pattern `x` as a
|
||||
binding _only_ if there is no variant named `x` in scope. A convention you can
|
||||
use to avoid conflicts is simply to name variants with upper-case letters, and
|
||||
local variables with lower-case letters.
|
||||
|
||||
Multiple match patterns may be joined with the `|` operator. A range of values
|
||||
may be specified with `...`. For example:
|
||||
|
||||
@ -3178,9 +3208,9 @@ may be specified with `...`. For example:
|
||||
# let x = 2;
|
||||
|
||||
let message = match x {
|
||||
0 | 1 => "not many",
|
||||
2 ... 9 => "a few",
|
||||
_ => "lots"
|
||||
0 | 1 => "not many",
|
||||
2 ... 9 => "a few",
|
||||
_ => "lots"
|
||||
};
|
||||
```
|
||||
|
||||
@ -3199,9 +3229,9 @@ may refer to the variables bound within the pattern they follow.
|
||||
# fn process_other(i: i32) { }
|
||||
|
||||
let message = match maybe_digit {
|
||||
Some(x) if x < 10 => process_digit(x),
|
||||
Some(x) => process_other(x),
|
||||
None => panic!()
|
||||
Some(x) if x < 10 => process_digit(x),
|
||||
Some(x) => process_other(x),
|
||||
None => panic!()
|
||||
};
|
||||
```
|
||||
|
||||
@ -3245,10 +3275,10 @@ An example of a `return` expression:
|
||||
|
||||
```
|
||||
fn max(a: i32, b: i32) -> i32 {
|
||||
if a > b {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
if a > b {
|
||||
return a;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
```
|
||||
|
||||
@ -3492,7 +3522,7 @@ An example of a `fn` type:
|
||||
|
||||
```
|
||||
fn add(x: i32, y: i32) -> i32 {
|
||||
return x + y;
|
||||
return x + y;
|
||||
}
|
||||
|
||||
let mut x = add(5,7);
|
||||
@ -3572,19 +3602,19 @@ An example of a trait object:
|
||||
|
||||
```
|
||||
trait Printable {
|
||||
fn stringify(&self) -> String;
|
||||
fn stringify(&self) -> String;
|
||||
}
|
||||
|
||||
impl Printable for i32 {
|
||||
fn stringify(&self) -> String { self.to_string() }
|
||||
fn stringify(&self) -> String { self.to_string() }
|
||||
}
|
||||
|
||||
fn print(a: Box<Printable>) {
|
||||
println!("{}", a.stringify());
|
||||
println!("{}", a.stringify());
|
||||
}
|
||||
|
||||
fn main() {
|
||||
print(Box::new(10) as Box<Printable>);
|
||||
print(Box::new(10) as Box<Printable>);
|
||||
}
|
||||
```
|
||||
|
||||
@ -3599,7 +3629,7 @@ its type parameters are types:
|
||||
```ignore
|
||||
fn to_vec<A: Clone>(xs: &[A]) -> Vec<A> {
|
||||
if xs.is_empty() {
|
||||
return vec![];
|
||||
return vec![];
|
||||
}
|
||||
let first: A = xs[0].clone();
|
||||
let mut rest: Vec<A> = to_vec(&xs[1..]);
|
||||
@ -3619,7 +3649,7 @@ it is an alias for the implementing type. For example, in:
|
||||
|
||||
```
|
||||
trait Printable {
|
||||
fn make_string(&self) -> String;
|
||||
fn make_string(&self) -> String;
|
||||
}
|
||||
|
||||
impl Printable for String {
|
||||
@ -3687,7 +3717,7 @@ sites are:
|
||||
fn bar(_: i8) { }
|
||||
|
||||
fn main() {
|
||||
bar(128);
|
||||
bar(128);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -26,7 +26,7 @@ Every guideline has a status:
|
||||
|
||||
One purpose of these guidelines is to reach decisions on a number of
|
||||
cross-cutting API and stylistic choices. Discussion and development of
|
||||
the guidelines will happen primarily on http://discuss.rust-lang.org/,
|
||||
the guidelines will happen primarily on https://internals.rust-lang.org/,
|
||||
using the Guidelines category. Discussion can also occur on the
|
||||
[guidelines issue tracker](https://github.com/rust-lang/rust-guidelines).
|
||||
|
||||
|
||||
@ -57,7 +57,7 @@ fn write_info(info: &Info) -> Result<(), IoError> {
|
||||
```
|
||||
|
||||
See
|
||||
[the `result` module documentation](http://static.rust-lang.org/doc/master/std/result/index.html#the-try!-macro)
|
||||
[the `result` module documentation](https://doc.rust-lang.org/stable/std/result/index.html#the-try!-macro)
|
||||
for more details.
|
||||
|
||||
### The `Result`-`impl` pattern [FIXME]
|
||||
|
||||
@ -94,7 +94,7 @@ aspects of the input that are not covered by the contract.
|
||||
### For obstructions, use `Result`
|
||||
|
||||
The
|
||||
[`Result<T,E>` type](http://static.rust-lang.org/doc/master/std/result/index.html)
|
||||
[`Result<T,E>` type](https://doc.rust-lang.org/stable/std/result/index.html)
|
||||
represents either a success (yielding `T`) or failure (yielding `E`). By
|
||||
returning a `Result`, a function allows its clients to discover and react to
|
||||
obstructions in a fine-grained way.
|
||||
|
||||
@ -124,7 +124,7 @@ that the caller already owns, for example to re-use a buffer:
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize>
|
||||
```
|
||||
|
||||
(From the [Reader trait](http://static.rust-lang.org/doc/master/std/io/trait.Reader.html#tymethod.read).)
|
||||
(From the [Read trait](https://doc.rust-lang.org/stable/std/io/trait.Read.html#tymethod.read).)
|
||||
|
||||
### Consider validating arguments, statically or dynamically. [FIXME: needs RFC]
|
||||
|
||||
@ -132,7 +132,7 @@ _Note: this material is closely related to
|
||||
[library-level guarantees](../../safety/lib-guarantees.md)._
|
||||
|
||||
Rust APIs do _not_ generally follow the
|
||||
[robustness principle](http://en.wikipedia.org/wiki/Robustness_principle): "be
|
||||
[robustness principle](https://en.wikipedia.org/wiki/Robustness_principle): "be
|
||||
conservative in what you send; be liberal in what you accept".
|
||||
|
||||
Instead, Rust code should _enforce_ the validity of input whenever practical.
|
||||
@ -147,24 +147,26 @@ Choose an argument type that rules out bad inputs.
|
||||
For example, prefer
|
||||
|
||||
```rust
|
||||
fn foo(a: ascii::Ascii) { ... }
|
||||
enum FooMode {
|
||||
Mode1,
|
||||
Mode2,
|
||||
Mode3,
|
||||
}
|
||||
fn foo(mode: FooMode) { ... }
|
||||
```
|
||||
|
||||
over
|
||||
|
||||
```rust
|
||||
fn foo(a: u8) { ... }
|
||||
fn foo(mode2: bool, mode3: bool) {
|
||||
assert!(!mode2 || !mode3);
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Note that
|
||||
[`ascii::Ascii`](http://static.rust-lang.org/doc/master/std/ascii/struct.Ascii.html)
|
||||
is a _wrapper_ around `u8` that guarantees the highest bit is zero; see
|
||||
[newtype patterns](../types/newtype.md) for more details on creating typesafe wrappers.
|
||||
|
||||
Static enforcement usually comes at little run-time cost: it pushes the
|
||||
costs to the boundaries (e.g. when a `u8` is first converted into an
|
||||
`Ascii`). It also catches bugs early, during compilation, rather than through
|
||||
run-time failures.
|
||||
costs to the boundaries. It also catches bugs early, during compilation,
|
||||
rather than through run-time failures.
|
||||
|
||||
On the other hand, some properties are difficult or impossible to
|
||||
express using types.
|
||||
@ -177,7 +179,7 @@ downsides:
|
||||
|
||||
1. Runtime overhead (unless checking can be done as part of processing the input).
|
||||
2. Delayed detection of bugs.
|
||||
3. Introduces failure cases, either via `fail!` or `Result`/`Option` types (see
|
||||
3. Introduces failure cases, either via `panic!` or `Result`/`Option` types (see
|
||||
the [error handling guidelines](../../errors/README.md)), which must then be
|
||||
dealt with by client code.
|
||||
|
||||
|
||||
@ -58,13 +58,13 @@ For modules that themselves have submodules, place the module in a separate
|
||||
directory (e.g., `bar/mod.rs` for a module `bar`) rather than the same directory.
|
||||
|
||||
Note the structure of
|
||||
[`std::io`](http://doc.rust-lang.org/std/io/). Many of the submodules lack
|
||||
[`std::io`](https://doc.rust-lang.org/std/io/). Many of the submodules lack
|
||||
children, like
|
||||
[`io::fs`](http://doc.rust-lang.org/std/io/fs/)
|
||||
[`io::fs`](https://doc.rust-lang.org/std/io/fs/)
|
||||
and
|
||||
[`io::stdio`](http://doc.rust-lang.org/std/io/stdio/).
|
||||
[`io::stdio`](https://doc.rust-lang.org/std/io/stdio/).
|
||||
On the other hand,
|
||||
[`io::net`](http://doc.rust-lang.org/std/io/net/)
|
||||
[`io::net`](https://doc.rust-lang.org/std/io/net/)
|
||||
contains submodules, so it lives in a separate directory:
|
||||
|
||||
```
|
||||
@ -88,7 +88,7 @@ submodules of `io::net` easier to find.
|
||||
### Consider top-level definitions or reexports. [FIXME: needs RFC]
|
||||
|
||||
For modules with submodules,
|
||||
define or [reexport](http://doc.rust-lang.org/std/io/#reexports) commonly used
|
||||
define or [reexport](https://doc.rust-lang.org/std/io/#reexports) commonly used
|
||||
definitions at the top level:
|
||||
|
||||
* Functionality relevant to the module itself or to many of its
|
||||
@ -98,10 +98,10 @@ definitions at the top level:
|
||||
common definitions.
|
||||
|
||||
For example,
|
||||
[`IoError`](http://doc.rust-lang.org/std/io/struct.IoError.html)
|
||||
[`IoError`](https://doc.rust-lang.org/std/io/struct.IoError.html)
|
||||
is defined in `io/mod.rs`, since it pertains to the entirety of `io`,
|
||||
while
|
||||
[`TcpStream`](http://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
|
||||
[`TcpStream`](https://doc.rust-lang.org/std/io/net/tcp/struct.TcpStream.html)
|
||||
is defined in `io/net/tcp.rs` and reexported in the `io` module.
|
||||
|
||||
### Use internal module hirearchies for organization. [FIXME: needs RFC]
|
||||
@ -113,11 +113,11 @@ is defined in `io/net/tcp.rs` and reexported in the `io` module.
|
||||
Internal module hirearchies (i.e., private submodules) may be used to
|
||||
hide implementation details that are not part of the module's API.
|
||||
|
||||
For example, in [`std::io`](http://doc.rust-lang.org/std/io/), `mod mem`
|
||||
For example, in [`std::io`](https://doc.rust-lang.org/std/io/), `mod mem`
|
||||
provides implementations for
|
||||
[`BufReader`](http://doc.rust-lang.org/std/io/struct.BufReader.html)
|
||||
[`BufReader`](https://doc.rust-lang.org/std/io/struct.BufReader.html)
|
||||
and
|
||||
[`BufWriter`](http://doc.rust-lang.org/std/io/struct.BufWriter.html),
|
||||
[`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html),
|
||||
but these are re-exported in `io/mod.rs` at the top level of the module:
|
||||
|
||||
```rust
|
||||
|
||||
@ -32,7 +32,7 @@ treatment of ownership, as described below.
|
||||
|
||||
In some cases, constructing the final `T` does not require the builder itself to
|
||||
be consumed. The follow variant on
|
||||
[`std::io::process::Command`](http://static.rust-lang.org/doc/master/std/io/process/struct.Command.html)
|
||||
[`std::process::Command`](https://doc.rust-lang.org/stable/std/process/struct.Command.html)
|
||||
is one example:
|
||||
|
||||
```rust
|
||||
|
||||
@ -13,7 +13,7 @@ even though some of these abstractions feel like those of a high-level
|
||||
language. Even then, Rust still allows precise control like a low-level
|
||||
language would.
|
||||
|
||||
[rust]: http://rust-lang.org
|
||||
[rust]: https://www.rust-lang.org
|
||||
|
||||
“The Rust Programming Language” is split into eight sections. This introduction
|
||||
is the first. After this:
|
||||
@ -24,7 +24,7 @@ is the first. After this:
|
||||
* [Syntax and Semantics][ss] - Each bit of Rust, broken down into small chunks.
|
||||
* [Nightly Rust][nr] - Cutting-edge features that aren’t in stable builds yet.
|
||||
* [Glossary][gl] - A reference of terms used in the book.
|
||||
* [Academic Research][ar] - Literature that influenced Rust.
|
||||
* [Bibliography][bi] - Background on Rust's influences, papers about Rust.
|
||||
|
||||
[gs]: getting-started.html
|
||||
[lr]: learn-rust.html
|
||||
@ -32,7 +32,7 @@ is the first. After this:
|
||||
[ss]: syntax-and-semantics.html
|
||||
[nr]: nightly-rust.html
|
||||
[gl]: glossary.html
|
||||
[ar]: academic-research.html
|
||||
[bi]: bibliography.html
|
||||
|
||||
After reading this introduction, you’ll want to dive into either ‘Learn Rust’
|
||||
or ‘Syntax and Semantics’, depending on your preference: ‘Learn Rust’ if you
|
||||
|
||||
@ -69,4 +69,4 @@
|
||||
* [Slice Patterns](slice-patterns.md)
|
||||
* [Associated Constants](associated-constants.md)
|
||||
* [Glossary](glossary.md)
|
||||
* [Academic Research](academic-research.md)
|
||||
* [Bibliography](bibliography.md)
|
||||
|
||||
@ -34,16 +34,16 @@ formal `#[link(...)]` attribute on `extern` blocks instead.
|
||||
|
||||
# Static linking
|
||||
|
||||
Static linking refers to the process of creating output that contain all
|
||||
required libraries and so don't need libraries installed on every system where
|
||||
Static linking refers to the process of creating output that contains all
|
||||
required libraries and so doesn't need libraries installed on every system where
|
||||
you want to use your compiled project. Pure-Rust dependencies are statically
|
||||
linked by default so you can use created binaries and libraries without
|
||||
installing the Rust everywhere. By contrast, native libraries
|
||||
(e.g. `libc` and `libm`) usually dynamically linked, but it is possible to
|
||||
installing Rust everywhere. By contrast, native libraries
|
||||
(e.g. `libc` and `libm`) are usually dynamically linked, but it is possible to
|
||||
change this and statically link them as well.
|
||||
|
||||
Linking is a very platform dependent topic — on some platforms, static linking
|
||||
may not be possible at all! This section assumes some basic familiarity with
|
||||
Linking is a very platform-dependent topic, and static linking may not even be
|
||||
possible on some platforms! This section assumes some basic familiarity with
|
||||
linking on your platform of choice.
|
||||
|
||||
## Linux
|
||||
@ -71,8 +71,7 @@ Dynamic linking on Linux can be undesirable if you wish to use new library
|
||||
features on old systems or target systems which do not have the required
|
||||
dependencies for your program to run.
|
||||
|
||||
Static linking is supported via an alternative `libc`, `musl` - this must be
|
||||
enabled at Rust compile-time with some prerequisites available. You can compile
|
||||
Static linking is supported via an alternative `libc`, `musl`. You can compile
|
||||
your own version of Rust with `musl` enabled and install it into a custom
|
||||
directory with the instructions below:
|
||||
|
||||
@ -81,33 +80,30 @@ $ mkdir musldist
|
||||
$ PREFIX=$(pwd)/musldist
|
||||
$
|
||||
$ # Build musl
|
||||
$ wget http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
|
||||
[...]
|
||||
$ curl -O http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
|
||||
$ tar xf musl-1.1.10.tar.gz
|
||||
$ cd musl-1.1.10/
|
||||
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
|
||||
[...]
|
||||
musl-1.1.10 $ make
|
||||
[...]
|
||||
musl-1.1.10 $ make install
|
||||
[...]
|
||||
musl-1.1.10 $ cd ..
|
||||
$ du -h musldist/lib/libc.a
|
||||
2.2M musldist/lib/libc.a
|
||||
$
|
||||
$ # Build libunwind.a
|
||||
$ wget http://llvm.org/releases/3.6.1/llvm-3.6.1.src.tar.xz
|
||||
$ tar xf llvm-3.6.1.src.tar.xz
|
||||
$ cd llvm-3.6.1.src/projects/
|
||||
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libcxxabi/trunk/ libcxxabi
|
||||
llvm-3.6.1.src/projects $ svn co http://llvm.org/svn/llvm-project/libunwind/trunk/ libunwind
|
||||
llvm-3.6.1.src/projects $ sed -i 's#^\(include_directories\).*$#\0\n\1(../libcxxabi/include)#' libunwind/CMakeLists.txt
|
||||
llvm-3.6.1.src/projects $ mkdir libunwind/build
|
||||
llvm-3.6.1.src/projects $ cd libunwind/build
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
|
||||
llvm-3.6.1.src/projects/libunwind/build $ make
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
|
||||
llvm-3.6.1.src/projects/libunwind/build $ cd cd ../../../../
|
||||
$ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz
|
||||
$ tar xf llvm-3.7.0.src.tar.xz
|
||||
$ cd llvm-3.7.0.src/projects/
|
||||
llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libcxxabi-3.7.0.src.tar.xz | tar xJf -
|
||||
llvm-3.7.0.src/projects $ mv libcxxabi-3.7.0.src libcxxabi
|
||||
llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf -
|
||||
llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind
|
||||
llvm-3.7.0.src/projects $ mkdir libunwind/build
|
||||
llvm-3.7.0.src/projects $ cd libunwind/build
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
|
||||
llvm-3.7.0.src/projects/libunwind/build $ make
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cd ../../../../
|
||||
$ du -h musldist/lib/libunwind.a
|
||||
164K musldist/lib/libunwind.a
|
||||
$
|
||||
@ -123,7 +119,7 @@ $ du -h musldist/bin/rustc
|
||||
```
|
||||
|
||||
You now have a build of a `musl`-enabled Rust! Because we've installed it to a
|
||||
custom prefix we need to make sure our system can the binaries and appropriate
|
||||
custom prefix we need to make sure our system can find the binaries and appropriate
|
||||
libraries when we try and run it:
|
||||
|
||||
```text
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
% Academic Research
|
||||
% Bibliography
|
||||
|
||||
An incomplete list of papers that have had some influence in Rust.
|
||||
|
||||
Recommended for inspiration and a better understanding of Rust's background.
|
||||
This is a reading list of material relevant to Rust. It includes prior
|
||||
research that has - at one time or another - influenced the design of
|
||||
Rust, as well as publications about Rust.
|
||||
|
||||
### Type system
|
||||
|
||||
@ -33,6 +33,7 @@ Recommended for inspiration and a better understanding of Rust's background.
|
||||
* [Non-blocking steal-half work queues](http://www.cs.bgu.ac.il/%7Ehendlerd/papers/p280-hendler.pdf)
|
||||
* [Reagents: expressing and composing fine-grained concurrency](http://www.mpi-sws.org/~turon/reagents.pdf)
|
||||
* [Algorithms for scalable synchronization of shared-memory multiprocessors](https://www.cs.rochester.edu/u/scott/papers/1991_TOCS_synch.pdf)
|
||||
* [Epoc-based reclamation](https://www.cl.cam.ac.uk/techreports/UCAM-CL-TR-579.pdf).
|
||||
|
||||
### Others
|
||||
|
||||
@ -71,3 +72,9 @@ Language](http://www.cs.indiana.edu/~eholk/papers/hips2013.pdf). Early GPU work
|
||||
* [Code Refinement of Stencil
|
||||
Codes](http://compilers.cs.uni-saarland.de/papers/ppl14_web.pdf). Another
|
||||
paper using Impala.
|
||||
* [Parallelization in Rust with fork-join and
|
||||
friends](http://publications.lib.chalmers.se/records/fulltext/219016/219016.pdf). Linus
|
||||
Farnstrand's master's thesis.
|
||||
* [Session Types for
|
||||
Rust](http://munksgaard.me/papers/laumann-munksgaard-larsen.pdf). Philip
|
||||
Munksgaard's master's thesis. Research for Servo.
|
||||
@ -1,6 +1,6 @@
|
||||
% Choosing your Guarantees
|
||||
|
||||
One important feature of Rust as language is that it lets us control the costs and guarantees
|
||||
One important feature of Rust is that it lets us control the costs and guarantees
|
||||
of a program.
|
||||
|
||||
There are various “wrapper type” abstractions in the Rust standard library which embody
|
||||
@ -18,9 +18,9 @@ Before proceeding, it is highly recommended that one reads about [ownership][own
|
||||
|
||||
## `Box<T>`
|
||||
|
||||
[`Box<T>`][box] is pointer which is “owned”, or a “box”. While it can hand
|
||||
out references to the contained data, it is the only owner of the data. In particular, when
|
||||
something like the following occurs:
|
||||
[`Box<T>`][box] is an “owned” pointer, or a “box”. While it can hand
|
||||
out references to the contained data, it is the only owner of the data. In particular, consider
|
||||
the following:
|
||||
|
||||
```rust
|
||||
let x = Box::new(1);
|
||||
@ -40,7 +40,7 @@ allowed to share references to this by the regular borrowing rules, checked at c
|
||||
|
||||
[box]: ../std/boxed/struct.Box.html
|
||||
|
||||
## `&T` and `&mut T`
|
||||
## `&T` and `&mut T`
|
||||
|
||||
These are immutable and mutable references respectively. They follow the “read-write lock”
|
||||
pattern, such that one may either have only one mutable reference to some data, or any number of
|
||||
@ -243,7 +243,7 @@ Many of the types above cannot be used in a threadsafe manner. Particularly, `Rc
|
||||
`RefCell<T>`, which both use non-atomic reference counts (_atomic_ reference counts are those which
|
||||
can be incremented from multiple threads without causing a data race), cannot be used this way. This
|
||||
makes them cheaper to use, but we need thread safe versions of these too. They exist, in the form of
|
||||
`Arc<T>` and `Mutex<T>`/`RWLock<T>`
|
||||
`Arc<T>` and `Mutex<T>`/`RwLock<T>`
|
||||
|
||||
Note that the non-threadsafe types _cannot_ be sent between threads, and this is checked at compile
|
||||
time.
|
||||
|
||||
@ -316,6 +316,35 @@ assert_eq!(3, answer);
|
||||
Now we take a trait object, a `&Fn`. And we have to make a reference
|
||||
to our closure when we pass it to `call_with_one`, so we use `&||`.
|
||||
|
||||
# Function pointers and closures
|
||||
|
||||
A function pointer is kind of like a closure that has no environment. As such,
|
||||
you can pass a function pointer to any function expecting a closure argument,
|
||||
and it will work:
|
||||
|
||||
```rust
|
||||
fn call_with_one(some_closure: &Fn(i32) -> i32) -> i32 {
|
||||
some_closure(1)
|
||||
}
|
||||
|
||||
fn add_one(i: i32) -> i32 {
|
||||
i + 1
|
||||
}
|
||||
|
||||
let f = add_one;
|
||||
|
||||
let answer = call_with_one(&f);
|
||||
|
||||
assert_eq!(2, answer);
|
||||
```
|
||||
|
||||
In this example, we don’t strictly need the intermediate variable `f`,
|
||||
the name of the function works just fine too:
|
||||
|
||||
```ignore
|
||||
let answer = call_with_one(&add_one);
|
||||
```
|
||||
|
||||
# Returning closures
|
||||
|
||||
It’s very common for functional-style code to return closures in various
|
||||
|
||||
@ -115,7 +115,7 @@ In addition to procedural macros, you can define new
|
||||
extensions. See
|
||||
[`Registry::register_syntax_extension`](../rustc/plugin/registry/struct.Registry.html#method.register_syntax_extension)
|
||||
and the [`SyntaxExtension`
|
||||
enum](http://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
|
||||
enum](https://doc.rust-lang.org/syntax/ext/base/enum.SyntaxExtension.html). For
|
||||
a more involved macro example, see
|
||||
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
|
||||
|
||||
@ -156,7 +156,7 @@ so that the compiler can continue and find further errors.
|
||||
To print syntax fragments for debugging, you can use
|
||||
[`span_note`](../syntax/ext/base/struct.ExtCtxt.html#method.span_note) together
|
||||
with
|
||||
[`syntax::print::pprust::*_to_string`](http://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
|
||||
[`syntax::print::pprust::*_to_string`](https://doc.rust-lang.org/syntax/print/pprust/index.html#functions).
|
||||
|
||||
The example above produced an integer literal using
|
||||
[`AstBuilder::expr_usize`](../syntax/ext/build/trait.AstBuilder.html#tymethod.expr_usize).
|
||||
|
||||
@ -135,28 +135,34 @@ This gives us an error:
|
||||
^~~~
|
||||
```
|
||||
|
||||
In this case, we know that our code _should_ be safe, but Rust isn't sure. And
|
||||
it's actually not safe: if we had a reference to `data` in each thread, and the
|
||||
thread takes ownership of the reference, we have three owners! That's bad. We
|
||||
can fix this by using the `Arc<T>` type, which is an atomic reference counted
|
||||
pointer. The 'atomic' part means that it's safe to share across threads.
|
||||
Rust knows this wouldn't be safe! If we had a reference to `data` in each
|
||||
thread, and the thread takes ownership of the reference, we'd have three
|
||||
owners!
|
||||
|
||||
So, we need some type that lets us have more than one reference to a value and
|
||||
that we can share between threads, that is it must implement `Sync`.
|
||||
|
||||
We'll use `Arc<T>`, rust's standard atomic reference count type, which
|
||||
wraps a value up with some extra runtime bookkeeping which allows us to
|
||||
share the ownership of the value between multiple references at the same time.
|
||||
|
||||
The bookkeeping consists of a count of how many of these references exist to
|
||||
the value, hence the reference count part of the name.
|
||||
|
||||
The Atomic part means `Arc<T>` can safely be accessed from multiple threads.
|
||||
To do this the compiler guarantees that mutations of the internal count use
|
||||
indivisible operations which can't have data races.
|
||||
|
||||
`Arc<T>` assumes one more property about its contents to ensure that it is safe
|
||||
to share across threads: it assumes its contents are `Sync`. But in our
|
||||
case, we want to be able to mutate the value. We need a type that can ensure
|
||||
only one person at a time can mutate what's inside. For that, we can use the
|
||||
`Mutex<T>` type. Here's the second version of our code. It still doesn't work,
|
||||
but for a different reason:
|
||||
|
||||
```ignore
|
||||
use std::thread;
|
||||
use std::sync::Mutex;
|
||||
use std::sync::Arc;
|
||||
|
||||
fn main() {
|
||||
let mut data = Mutex::new(vec![1, 2, 3]);
|
||||
let mut data = Arc::new(vec![1, 2, 3]);
|
||||
|
||||
for i in 0..3 {
|
||||
let data = data.lock().unwrap();
|
||||
let data = data.clone();
|
||||
thread::spawn(move || {
|
||||
data[i] += 1;
|
||||
});
|
||||
@ -166,29 +172,29 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Here's the error:
|
||||
We now call `clone()` on our `Arc<T>`, which increases the internal count.
|
||||
This handle is then moved into the new thread.
|
||||
|
||||
And... still gives us an error.
|
||||
|
||||
```text
|
||||
<anon>:9:9: 9:22 error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
|
||||
<anon>:11 thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
<anon>:9:9: 9:22 note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
|
||||
<anon>:11 thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
<anon>:11:24 error: cannot borrow immutable borrowed content as mutable
|
||||
<anon>:11 data[i] += 1;
|
||||
^~~~
|
||||
```
|
||||
|
||||
You see, [`Mutex`](../std/sync/struct.Mutex.html) has a
|
||||
[`lock`](../std/sync/struct.Mutex.html#method.lock)
|
||||
method which has this signature:
|
||||
`Arc<T>` assumes one more property about its contents to ensure that it is safe
|
||||
to share across threads: it assumes its contents are `Sync`. This is true for
|
||||
our value if it's immutable, but we want to be able to mutate it, so we need
|
||||
something else to persuade the borrow checker we know what we're doing.
|
||||
|
||||
```ignore
|
||||
fn lock(&self) -> LockResult<MutexGuard<T>>
|
||||
```
|
||||
It looks like we need some type that allows us to safely mutate a shared value,
|
||||
for example a type that that can ensure only one thread at a time is able to
|
||||
mutate the value inside it at any one time.
|
||||
|
||||
Because `Send` is not implemented for `MutexGuard<T>`, we can't transfer the
|
||||
guard across thread boundaries, which gives us our error.
|
||||
For that, we can use the `Mutex<T>` type!
|
||||
|
||||
We can use `Arc<T>` to fix this. Here's the working version:
|
||||
Here's the working version:
|
||||
|
||||
```rust
|
||||
use std::sync::{Arc, Mutex};
|
||||
@ -209,9 +215,31 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
We now call `clone()` on our `Arc`, which increases the internal count. This
|
||||
handle is then moved into the new thread. Let's examine the body of the
|
||||
thread more closely:
|
||||
|
||||
If we'd tried to use `Mutex<T>` without wrapping it in an `Arc<T>` we would have
|
||||
seen another error like:
|
||||
|
||||
```text
|
||||
error: the trait `core::marker::Send` is not implemented for the type `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` [E0277]
|
||||
thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
note: `std::sync::mutex::MutexGuard<'_, collections::vec::Vec<u32>>` cannot be sent between threads safely
|
||||
thread::spawn(move || {
|
||||
^~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
You see, [`Mutex`](../std/sync/struct.Mutex.html) has a
|
||||
[`lock`](../std/sync/struct.Mutex.html#method.lock)
|
||||
method which has this signature:
|
||||
|
||||
```ignore
|
||||
fn lock(&self) -> LockResult<MutexGuard<T>>
|
||||
```
|
||||
|
||||
and because `Send` is not implemented for `MutexGuard<T>`, we couldn't have
|
||||
transferred the guard across thread boundaries on it's own.
|
||||
|
||||
Let's examine the body of the thread more closely:
|
||||
|
||||
```rust
|
||||
# use std::sync::{Arc, Mutex};
|
||||
@ -315,12 +343,14 @@ threads as a simple isolation mechanism:
|
||||
```rust
|
||||
use std::thread;
|
||||
|
||||
let result = thread::spawn(move || {
|
||||
let handle = thread::spawn(move || {
|
||||
panic!("oops!");
|
||||
}).join();
|
||||
});
|
||||
|
||||
let result = handle.join();
|
||||
|
||||
assert!(result.is_err());
|
||||
```
|
||||
|
||||
Our `Thread` gives us a `Result` back, which allows us to check if the thread
|
||||
`Thread.join()` gives us a `Result` back, which allows us to check if the thread
|
||||
has panicked or not.
|
||||
|
||||
@ -115,7 +115,7 @@ $ ls target/debug
|
||||
build deps examples libphrases-a7448e02a0468eaa.rlib native
|
||||
```
|
||||
|
||||
`libphrase-hash.rlib` is the compiled crate. Before we see how to use this
|
||||
`libphrases-hash.rlib` is the compiled crate. Before we see how to use this
|
||||
crate from another crate, let’s break it up into multiple files.
|
||||
|
||||
# Multiple file crates
|
||||
@ -263,6 +263,10 @@ the `phrases` crate. We can then use `phrases`’ modules in this one. As we
|
||||
mentioned earlier, you can use double colons to refer to sub-modules and the
|
||||
functions inside of them.
|
||||
|
||||
(Note: when importing a crate that has dashes in its name "like-this", which is
|
||||
not a valid Rust identifier, it will be converted by changing the dashes to
|
||||
underscores, so you would write `extern crate like_this;`.)
|
||||
|
||||
Also, Cargo assumes that `src/main.rs` is the crate root of a binary crate,
|
||||
rather than a library crate. Our package now has two crates: `src/lib.rs` and
|
||||
`src/main.rs`. This pattern is quite common for executable crates: most
|
||||
@ -532,3 +536,51 @@ Goodbye in English: Goodbye.
|
||||
Hello in Japanese: こんにちは
|
||||
Goodbye in Japanese: さようなら
|
||||
```
|
||||
|
||||
## Complex imports
|
||||
|
||||
Rust offers several advanced options that can add compactness and
|
||||
convenience to your `extern crate` and `use` statements. Here is an example:
|
||||
|
||||
```rust,ignore
|
||||
extern crate phrases as sayings;
|
||||
|
||||
use sayings::japanese::greetings as ja_greetings;
|
||||
use sayings::japanese::farewells::*;
|
||||
use sayings::english::{self, greetings as en_greetings, farewells as en_farewells};
|
||||
|
||||
fn main() {
|
||||
println!("Hello in English; {}", en_greetings::hello());
|
||||
println!("And in Japanese: {}", ja_greetings::hello());
|
||||
println!("Goodbye in English: {}", english::farewells::goodbye());
|
||||
println!("Again: {}", en_farewells::goodbye());
|
||||
println!("And in Japanese: {}", goodbye());
|
||||
}
|
||||
```
|
||||
|
||||
What's going on here?
|
||||
|
||||
First, both `extern crate` and `use` allow renaming the thing that is being
|
||||
imported. So the crate is still called "phrases", but here we will refer
|
||||
to it as "sayings". Similarly, the first `use` statement pulls in the
|
||||
`japanese::farewells` module from the crate, but makes it available as
|
||||
`jp_farewells` as opposed to simply `farewells`. This can help to avoid
|
||||
ambiguity when importing similarly-named items from different places.
|
||||
|
||||
The second `use` statement uses a star glob to bring in _all_ symbols from the
|
||||
`sayings::japanese::farewells` module. As you can see we can later refer to
|
||||
the Japanese `goodbye` function with no module qualifiers. This kind of glob
|
||||
should be used sparingly.
|
||||
|
||||
The third `use` statement bears more explanation. It's using "brace expansion"
|
||||
globbing to compress three `use` statements into one (this sort of syntax
|
||||
may be familiar if you've written Linux shell scripts before). The
|
||||
uncompressed form of this statement would be:
|
||||
```rust,ignore
|
||||
use sayings::english;
|
||||
use sayings::english::greetings as en_greetings;
|
||||
use sayings::english::farewells as en_farewells;
|
||||
```
|
||||
As you can see, the curly brackets compress `use` statements for several items
|
||||
under the same path, and in this context `self` just refers back to that path.
|
||||
Note: The curly brackets cannot be nested or mixed with star globbing.
|
||||
|
||||
@ -89,8 +89,8 @@ Vectors can `Deref` to a slice.
|
||||
|
||||
## Deref and method calls
|
||||
|
||||
`Deref` will also kick in when calling a method. In other words, these are
|
||||
the same two things in Rust:
|
||||
`Deref` will also kick in when calling a method. Consider the following
|
||||
example.
|
||||
|
||||
```rust
|
||||
struct Foo;
|
||||
@ -99,13 +99,13 @@ impl Foo {
|
||||
fn foo(&self) { println!("Foo"); }
|
||||
}
|
||||
|
||||
let f = Foo;
|
||||
let f = &&Foo;
|
||||
|
||||
f.foo();
|
||||
```
|
||||
|
||||
Even though `f` isn’t a reference, and `foo` takes `&self`, this works.
|
||||
That’s because these things are the same:
|
||||
Even though `f` is a `&&Foo` and `foo` takes `&self`, this works. That’s
|
||||
because these things are the same:
|
||||
|
||||
```rust,ignore
|
||||
f.foo();
|
||||
|
||||
@ -73,10 +73,10 @@ hello.rs:4 }
|
||||
```
|
||||
|
||||
This [unfortunate error](https://github.com/rust-lang/rust/issues/22547) is
|
||||
correct: documentation comments apply to the thing after them, and there's no
|
||||
thing after that last comment.
|
||||
correct: documentation comments apply to the thing after them, and there's
|
||||
nothing after that last comment.
|
||||
|
||||
[rc-new]: http://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new
|
||||
[rc-new]: https://doc.rust-lang.org/nightly/std/rc/struct.Rc.html#method.new
|
||||
|
||||
### Writing documentation comments
|
||||
|
||||
@ -196,10 +196,10 @@ This will highlight according to whatever language you're showing off.
|
||||
If you're just showing plain text, choose `text`.
|
||||
|
||||
It's important to choose the correct annotation here, because `rustdoc` uses it
|
||||
in an interesting way: It can be used to actually test your examples, so that
|
||||
they don't get out of date. If you have some C code but `rustdoc` thinks it's
|
||||
Rust because you left off the annotation, `rustdoc` will complain when trying to
|
||||
generate the documentation.
|
||||
in an interesting way: It can be used to actually test your examples in a
|
||||
library crate, so that they don't get out of date. If you have some C code but
|
||||
`rustdoc` thinks it's Rust because you left off the annotation, `rustdoc` will
|
||||
complain when trying to generate the documentation.
|
||||
|
||||
## Documentation as tests
|
||||
|
||||
@ -377,8 +377,8 @@ $ rustdoc --test path/to/my/crate/root.rs
|
||||
$ cargo test
|
||||
```
|
||||
|
||||
That's right, `cargo test` tests embedded documentation too. However,
|
||||
`cargo test` will not test binary crates, only library ones. This is
|
||||
That's right, `cargo test` tests embedded documentation too. **However,
|
||||
`cargo test` will not test binary crates, only library ones.** This is
|
||||
due to the way `rustdoc` works: it links against the library to be tested,
|
||||
but with a binary, there’s nothing to link to.
|
||||
|
||||
@ -544,9 +544,9 @@ You can control a few aspects of the HTML that `rustdoc` generates through the
|
||||
`#![doc]` version of the attribute:
|
||||
|
||||
```rust
|
||||
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "http://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "http://doc.rust-lang.org/")]
|
||||
#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
|
||||
html_favicon_url = "https://www.rust-lang.org/favicon.ico",
|
||||
html_root_url = "https://doc.rust-lang.org/")]
|
||||
```
|
||||
|
||||
This sets a few different options, with a logo, favicon, and a root URL.
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -496,9 +496,11 @@ strings are not terminated with `\0`. If you need a NUL-terminated string for
|
||||
interoperability with C, you should use the `CString` type in the `std::ffi`
|
||||
module.
|
||||
|
||||
The standard library includes type aliases and function definitions for the C
|
||||
standard library in the `libc` module, and Rust links against `libc` and `libm`
|
||||
by default.
|
||||
The [`libc` crate on crates.io][libc] includes type aliases and function
|
||||
definitions for the C standard library in the `libc` module, and Rust links
|
||||
against `libc` and `libm` by default.
|
||||
|
||||
[libc]: https://crates.io/crates/libc
|
||||
|
||||
# The "nullable pointer optimization"
|
||||
|
||||
@ -555,3 +557,56 @@ pub extern fn oh_no() -> i32 {
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
# Representing opaque structs
|
||||
|
||||
Sometimes, a C library wants to provide a pointer to something, but not let you
|
||||
know the internal details of the thing it wants. The simplest way is to use a
|
||||
`void *` argument:
|
||||
|
||||
```c
|
||||
void foo(void *arg);
|
||||
void bar(void *arg);
|
||||
```
|
||||
|
||||
We can represent this in Rust with the `c_void` type:
|
||||
|
||||
```rust
|
||||
# #![feature(libc)]
|
||||
extern crate libc;
|
||||
|
||||
extern "C" {
|
||||
pub fn foo(arg: *mut libc::c_void);
|
||||
pub fn bar(arg: *mut libc::c_void);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
This is a perfectly valid way of handling the situation. However, we can do a bit
|
||||
better. To solve this, some C libraries will instead create a `struct`, where
|
||||
the details and memory layout of the struct are private. This gives some amount
|
||||
of type safety. These structures are called ‘opaque’. Here’s an example, in C:
|
||||
|
||||
```c
|
||||
struct Foo; /* Foo is a structure, but its contents are not part of the public interface */
|
||||
struct Bar;
|
||||
void foo(struct Foo *arg);
|
||||
void bar(struct Bar *arg);
|
||||
```
|
||||
|
||||
To do this in Rust, let’s create our own opaque types with `enum`:
|
||||
|
||||
```rust
|
||||
pub enum Foo {}
|
||||
pub enum Bar {}
|
||||
|
||||
extern "C" {
|
||||
pub fn foo(arg: *mut Foo);
|
||||
pub fn bar(arg: *mut Bar);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
By using an `enum` with no variants, we create an opaque type that we can’t
|
||||
instantiate, as it has no variants. But because our `Foo` and `Bar` types are
|
||||
different, we’ll get type safety between the two of them, so we cannot
|
||||
accidentally pass a pointer to `Foo` to `bar()`.
|
||||
|
||||
@ -214,11 +214,61 @@ fn diverges() -> ! {
|
||||
|
||||
`panic!` is a macro, similar to `println!()` that we’ve already seen. Unlike
|
||||
`println!()`, `panic!()` causes the current thread of execution to crash with
|
||||
the given message.
|
||||
the given message. Because this function will cause a crash, it will never
|
||||
return, and so it has the type ‘`!`’, which is read ‘diverges’.
|
||||
|
||||
Because this function will cause a crash, it will never return, and so it has
|
||||
the type ‘`!`’, which is read ‘diverges’. A diverging function can be used
|
||||
as any type:
|
||||
If you add a main function that calls `diverges()` and run it, you’ll get
|
||||
some output that looks like this:
|
||||
|
||||
```text
|
||||
thread ‘<main>’ panicked at ‘This function never returns!’, hello.rs:2
|
||||
```
|
||||
|
||||
If you want more information, you can get a backtrace by setting the
|
||||
`RUST_BACKTRACE` environment variable:
|
||||
|
||||
```text
|
||||
$ RUST_BACKTRACE=1 ./diverges
|
||||
thread '<main>' panicked at 'This function never returns!', hello.rs:2
|
||||
stack backtrace:
|
||||
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
|
||||
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
|
||||
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
|
||||
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
|
||||
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
|
||||
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
|
||||
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
|
||||
8: 0x7f402773d1d8 - __rust_try
|
||||
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
|
||||
10: 0x7f4027738a19 - main
|
||||
11: 0x7f402694ab44 - __libc_start_main
|
||||
12: 0x7f40277386c8 - <unknown>
|
||||
13: 0x0 - <unknown>
|
||||
```
|
||||
|
||||
`RUST_BACKTRACE` also works with Cargo’s `run` command:
|
||||
|
||||
```text
|
||||
$ RUST_BACKTRACE=1 cargo run
|
||||
Running `target/debug/diverges`
|
||||
thread '<main>' panicked at 'This function never returns!', hello.rs:2
|
||||
stack backtrace:
|
||||
1: 0x7f402773a829 - sys::backtrace::write::h0942de78b6c02817K8r
|
||||
2: 0x7f402773d7fc - panicking::on_panic::h3f23f9d0b5f4c91bu9w
|
||||
3: 0x7f402773960e - rt::unwind::begin_unwind_inner::h2844b8c5e81e79558Bw
|
||||
4: 0x7f4027738893 - rt::unwind::begin_unwind::h4375279447423903650
|
||||
5: 0x7f4027738809 - diverges::h2266b4c4b850236beaa
|
||||
6: 0x7f40277389e5 - main::h19bb1149c2f00ecfBaa
|
||||
7: 0x7f402773f514 - rt::unwind::try::try_fn::h13186883479104382231
|
||||
8: 0x7f402773d1d8 - __rust_try
|
||||
9: 0x7f402773f201 - rt::lang_start::ha172a3ce74bb453aK5w
|
||||
10: 0x7f4027738a19 - main
|
||||
11: 0x7f402694ab44 - __libc_start_main
|
||||
12: 0x7f40277386c8 - <unknown>
|
||||
13: 0x0 - <unknown>
|
||||
```
|
||||
|
||||
A diverging function can be used as any type:
|
||||
|
||||
```should_panic
|
||||
# fn diverges() -> ! {
|
||||
@ -227,3 +277,34 @@ as any type:
|
||||
let x: i32 = diverges();
|
||||
let x: String = diverges();
|
||||
```
|
||||
|
||||
## Function pointers
|
||||
|
||||
We can also create variable bindings which point to functions:
|
||||
|
||||
```rust
|
||||
let f: fn(i32) -> i32;
|
||||
```
|
||||
|
||||
`f` is a variable binding which points to a function that takes an `i32` as
|
||||
an argument and returns an `i32`. For example:
|
||||
|
||||
```rust
|
||||
fn plus_one(i: i32) -> i32 {
|
||||
i + 1
|
||||
}
|
||||
|
||||
// without type inference
|
||||
let f: fn(i32) -> i32 = plus_one;
|
||||
|
||||
// with type inference
|
||||
let f = plus_one;
|
||||
```
|
||||
|
||||
We can then use `f` to call the function:
|
||||
|
||||
```rust
|
||||
# fn plus_one(i: i32) -> i32 { i + 1 }
|
||||
# let f = plus_one;
|
||||
let six = f(5);
|
||||
```
|
||||
|
||||
@ -6,7 +6,7 @@ Generics are called ‘parametric polymorphism’ in type theory,
|
||||
which means that they are types or functions that have multiple forms (‘poly’
|
||||
is multiple, ‘morph’ is form) over a given parameter (‘parametric’).
|
||||
|
||||
Anyway, enough with type theory, let’s check out some generic code. Rust’s
|
||||
Anyway, enough type theory, let’s check out some generic code. Rust’s
|
||||
standard library provides a type, `Option<T>`, that’s generic:
|
||||
|
||||
```rust
|
||||
@ -17,7 +17,7 @@ enum Option<T> {
|
||||
```
|
||||
|
||||
The `<T>` part, which you’ve seen a few times before, indicates that this is
|
||||
a generic data type. Inside the declaration of our enum, wherever we see a `T`,
|
||||
a generic data type. Inside the declaration of our `enum`, wherever we see a `T`,
|
||||
we substitute that type for the same type used in the generic. Here’s an
|
||||
example of using `Option<T>`, with some extra type annotations:
|
||||
|
||||
@ -27,7 +27,7 @@ let x: Option<i32> = Some(5);
|
||||
|
||||
In the type declaration, we say `Option<i32>`. Note how similar this looks to
|
||||
`Option<T>`. So, in this particular `Option`, `T` has the value of `i32`. On
|
||||
the right-hand side of the binding, we do make a `Some(T)`, where `T` is `5`.
|
||||
the right-hand side of the binding, we make a `Some(T)`, where `T` is `5`.
|
||||
Since that’s an `i32`, the two sides match, and Rust is happy. If they didn’t
|
||||
match, we’d get an error:
|
||||
|
||||
@ -101,11 +101,6 @@ fn takes_two_things<T, U>(x: T, y: U) {
|
||||
}
|
||||
```
|
||||
|
||||
Generic functions are most useful with ‘trait bounds’, which we’ll cover in the
|
||||
[section on traits][traits].
|
||||
|
||||
[traits]: traits.html
|
||||
|
||||
## Generic structs
|
||||
|
||||
You can store a generic type in a `struct` as well:
|
||||
@ -120,5 +115,30 @@ let int_origin = Point { x: 0, y: 0 };
|
||||
let float_origin = Point { x: 0.0, y: 0.0 };
|
||||
```
|
||||
|
||||
Similarly to functions, the `<T>` is where we declare the generic parameters,
|
||||
Similar to functions, the `<T>` is where we declare the generic parameters,
|
||||
and we then use `x: T` in the type declaration, too.
|
||||
|
||||
When you want to add an implementation for the generic `struct`, you just
|
||||
declare the type parameter after the `impl`:
|
||||
|
||||
```rust
|
||||
# struct Point<T> {
|
||||
# x: T,
|
||||
# y: T,
|
||||
# }
|
||||
#
|
||||
impl<T> Point<T> {
|
||||
fn swap(&mut self) {
|
||||
std::mem::swap(&mut self.x, &mut self.y);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
So far you’ve seen generics that take absolutely any type. These are useful in
|
||||
many cases: you’ve already seen `Option<T>`, and later you’ll meet universal
|
||||
container types like [`Vec<T>`][Vec]. On the other hand, often you want to
|
||||
trade that flexibility for increased expressive power. Read about [trait
|
||||
bounds][traits] to see why and how.
|
||||
|
||||
[traits]: traits.html
|
||||
[Vec]: ../std/vec/struct.Vec.html
|
||||
|
||||
@ -38,6 +38,12 @@ let z = (8, 2, 6);
|
||||
|
||||
In the example above `x` and `y` have arity 2. `z` has arity 3.
|
||||
|
||||
### DST (Dynamically Sized Type)
|
||||
|
||||
A type without a statically known size or alignment. ([more info][link])
|
||||
|
||||
[link]: ../nomicon/exotic-sizes.html#dynamically-sized-types-(dsts)
|
||||
|
||||
### Expression
|
||||
|
||||
In computer programming, an expression is a combination of values, constants,
|
||||
|
||||
@ -533,7 +533,7 @@ Great! Next up: let’s compare our guess to the secret guess.
|
||||
# Comparing guesses
|
||||
|
||||
Now that we’ve got user input, let’s compare our guess to the random guess.
|
||||
Here’s our next step, though it doesn’t quite work yet:
|
||||
Here’s our next step, though it doesn’t quite compile yet:
|
||||
|
||||
```rust,ignore
|
||||
extern crate rand;
|
||||
@ -617,7 +617,7 @@ match guess.cmp(&secret_number) {
|
||||
If it’s `Less`, we print `Too small!`, if it’s `Greater`, `Too big!`, and if
|
||||
`Equal`, `You win!`. `match` is really useful, and is used often in Rust.
|
||||
|
||||
I did mention that this won’t quite work yet, though. Let’s try it:
|
||||
I did mention that this won’t quite compile yet, though. Let’s try it:
|
||||
|
||||
```bash
|
||||
$ cargo build
|
||||
|
||||
@ -32,7 +32,7 @@ install dialog and on the "Product Features" page ensure "Add to PATH" is
|
||||
installed on the local hard drive.
|
||||
|
||||
|
||||
[install-page]: http://www.rust-lang.org/install.html
|
||||
[install-page]: https://www.rust-lang.org/install.html
|
||||
|
||||
## Uninstalling
|
||||
|
||||
@ -85,10 +85,10 @@ $ rustc --version
|
||||
```
|
||||
|
||||
You should see the version number, commit hash, and commit date. If you just
|
||||
installed version 1.0.0, you should see:
|
||||
installed version 1.2.0, you should see:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0 (a59de37e9 2015-05-13)
|
||||
rustc 1.2.0 (082e47636 2015-08-03)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
@ -112,5 +112,5 @@ resources include [the user’s forum][users], and
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[users]: https://users.rust-lang.org/
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
||||
@ -51,7 +51,6 @@ fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
|
||||
@ -77,8 +77,18 @@ Before we get to that, though, let’s break the explicit example down:
|
||||
fn bar<'a>(...)
|
||||
```
|
||||
|
||||
This part declares our lifetimes. This says that `bar` has one lifetime, `'a`.
|
||||
If we had two reference parameters, it would look like this:
|
||||
We previously talked a little about [function syntax][functions], but we didn’t
|
||||
discuss the `<>`s after a function’s name. A function can have ‘generic
|
||||
parameters’ between the `<>`s, of which lifetimes are one kind. We’ll discuss
|
||||
other kinds of generics [later in the book][generics], but for now, let’s
|
||||
just focus on the lifetimes aspect.
|
||||
|
||||
[functions]: functions.html
|
||||
[generics]: generics.html
|
||||
|
||||
We use `<>` to declare our lifetimes. This says that `bar` has one lifetime,
|
||||
`'a`. If we had two reference parameters, it would look like this:
|
||||
|
||||
|
||||
```rust,ignore
|
||||
fn bar<'a, 'b>(...)
|
||||
@ -98,7 +108,7 @@ If we wanted an `&mut` reference, we’d do this:
|
||||
|
||||
If you compare `&mut i32` to `&'a mut i32`, they’re the same, it’s just that
|
||||
the lifetime `'a` has snuck in between the `&` and the `mut i32`. We read `&mut
|
||||
i32` as ‘a mutable reference to an i32’ and `&'a mut i32` as ‘a mutable
|
||||
i32` as ‘a mutable reference to an `i32`’ and `&'a mut i32` as ‘a mutable
|
||||
reference to an `i32` with the lifetime `'a`’.
|
||||
|
||||
# In `struct`s
|
||||
|
||||
@ -134,7 +134,7 @@ Outputs:
|
||||
```text
|
||||
0: Content of line one
|
||||
1: Content of line two
|
||||
2: Content of line tree
|
||||
2: Content of line three
|
||||
3: Content of line four
|
||||
```
|
||||
|
||||
@ -193,7 +193,7 @@ for x in 0..10 {
|
||||
You may also encounter situations where you have nested loops and need to
|
||||
specify which one your `break` or `continue` statement is for. Like most
|
||||
other languages, by default a `break` or `continue` will apply to innermost
|
||||
loop. In a sitation where you would like to a `break` or `continue` for one
|
||||
loop. In a situation where you would like to a `break` or `continue` for one
|
||||
of the outer loops, you can use labels to specify which loop the `break` or
|
||||
`continue` statement applies to. This will only print when both `x` and `y` are
|
||||
odd:
|
||||
|
||||
@ -313,7 +313,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
This works because Rust has a [hygienic macro system][]. Each macro expansion
|
||||
This works because Rust has a [hygienic macro system]. Each macro expansion
|
||||
happens in a distinct ‘syntax context’, and each variable is tagged with the
|
||||
syntax context where it was introduced. It’s as though the variable `state`
|
||||
inside `main` is painted a different "color" from the variable `state` inside
|
||||
|
||||
@ -7,7 +7,7 @@ can be awkward. Consider this code:
|
||||
baz(bar(foo));
|
||||
```
|
||||
|
||||
We would read this left-to right, and so we see ‘baz bar foo’. But this isn’t the
|
||||
We would read this left-to-right, and so we see ‘baz bar foo’. But this isn’t the
|
||||
order that the functions would get called in, that’s inside-out: ‘foo bar baz’.
|
||||
Wouldn’t it be nice if we could do this instead?
|
||||
|
||||
@ -45,17 +45,17 @@ This will print `12.566371`.
|
||||
|
||||
|
||||
|
||||
We’ve made a struct that represents a circle. We then write an `impl` block,
|
||||
We’ve made a `struct` that represents a circle. We then write an `impl` block,
|
||||
and inside it, define a method, `area`.
|
||||
|
||||
Methods take a special first parameter, of which there are three variants:
|
||||
Methods take a special first parameter, of which there are three variants:
|
||||
`self`, `&self`, and `&mut self`. You can think of this first parameter as
|
||||
being the `foo` in `foo.bar()`. The three variants correspond to the three
|
||||
kinds of things `foo` could be: `self` if it’s just a value on the stack,
|
||||
`&self` if it’s a reference, and `&mut self` if it’s a mutable reference.
|
||||
Because we took the `&self` parameter to `area`, we can use it just like any
|
||||
other parameter. Because we know it’s a `Circle`, we can access the `radius`
|
||||
just like we would with any other struct.
|
||||
just like we would with any other `struct`.
|
||||
|
||||
We should default to using `&self`, as you should prefer borrowing over taking
|
||||
ownership, as well as taking immutable references over mutable ones. Here’s an
|
||||
@ -120,12 +120,12 @@ Check the return type:
|
||||
```rust
|
||||
# struct Circle;
|
||||
# impl Circle {
|
||||
fn grow(&self) -> Circle {
|
||||
fn grow(&self, increment: f64) -> Circle {
|
||||
# Circle } }
|
||||
```
|
||||
|
||||
We just say we’re returning a `Circle`. With this method, we can grow a new
|
||||
circle to any arbitrary size.
|
||||
`Circle` to any arbitrary size.
|
||||
|
||||
# Associated functions
|
||||
|
||||
@ -161,7 +161,7 @@ methods’.
|
||||
|
||||
# Builder Pattern
|
||||
|
||||
Let’s say that we want our users to be able to create Circles, but we will
|
||||
Let’s say that we want our users to be able to create `Circle`s, but we will
|
||||
allow them to only set the properties they care about. Otherwise, the `x`
|
||||
and `y` attributes will be `0.0`, and the `radius` will be `1.0`. Rust doesn’t
|
||||
have method overloading, named arguments, or variable arguments. We employ
|
||||
@ -224,7 +224,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
What we’ve done here is make another struct, `CircleBuilder`. We’ve defined our
|
||||
What we’ve done here is make another `struct`, `CircleBuilder`. We’ve defined our
|
||||
builder methods on it. We’ve also defined our `area()` method on `Circle`. We
|
||||
also made one more method on `CircleBuilder`: `finalize()`. This method creates
|
||||
our final `Circle` from the builder. Now, we’ve used the type system to enforce
|
||||
|
||||
@ -62,7 +62,7 @@ fn foo(mut x: i32) {
|
||||
# Interior vs. Exterior Mutability
|
||||
|
||||
However, when we say something is ‘immutable’ in Rust, that doesn’t mean that
|
||||
it’s not able to be changed: We mean something has ‘exterior mutability’. Consider,
|
||||
it’s not able to be changed: we mean something has ‘exterior mutability’. Consider,
|
||||
for example, [`Arc<T>`][arc]:
|
||||
|
||||
```rust
|
||||
@ -85,8 +85,8 @@ philosophy, memory safety, and the mechanism by which Rust guarantees it, the
|
||||
> You may have one or the other of these two kinds of borrows, but not both at
|
||||
> the same time:
|
||||
>
|
||||
> * one or more references (`&T`) to a resource.
|
||||
> * exactly one mutable reference (`&mut T`)
|
||||
> * one or more references (`&T`) to a resource,
|
||||
> * exactly one mutable reference (`&mut T`).
|
||||
|
||||
[ownership]: ownership.html
|
||||
[borrowing]: references-and-borrowing.html#borrowing
|
||||
|
||||
@ -50,7 +50,7 @@ documentation on [building Rust from Source][from-source], or [the official
|
||||
binary downloads][install-page].
|
||||
|
||||
[from-source]: https://github.com/rust-lang/rust#building-from-source
|
||||
[install-page]: http://www.rust-lang.org/install.html
|
||||
[install-page]: https://www.rust-lang.org/install.html
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
@ -95,5 +95,5 @@ resources include [the user’s forum][users], and [Stack Overflow][stackoverflo
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: http://users.rust-lang.org/
|
||||
[users]: https://users.rust-lang.org/
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
||||
@ -36,7 +36,6 @@ fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
// These functions and traits are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
@ -61,7 +60,6 @@ pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
@ -73,18 +71,12 @@ The compiler currently makes a few assumptions about symbols which are available
|
||||
in the executable to call. Normally these functions are provided by the standard
|
||||
library, but without it you must define your own.
|
||||
|
||||
The first of these three functions, `stack_exhausted`, is invoked whenever stack
|
||||
overflow is detected. This function has a number of restrictions about how it
|
||||
can be called and what it must do, but if the stack limit register is not being
|
||||
maintained then a thread always has an "infinite stack" and this function
|
||||
shouldn't get triggered.
|
||||
|
||||
The second of these three functions, `eh_personality`, is used by the
|
||||
The first of these two functions, `eh_personality`, is used by the
|
||||
failure mechanisms of the compiler. This is often mapped to GCC's
|
||||
personality function (see the
|
||||
[libstd implementation](../std/rt/unwind/index.html) for more
|
||||
information), but crates which do not trigger a panic can be assured
|
||||
that this function is never called. The final function, `panic_fmt`, is
|
||||
that this function is never called. The second function, `panic_fmt`, is
|
||||
also used by the failure mechanisms of the compiler.
|
||||
|
||||
## Using libcore
|
||||
@ -150,7 +142,6 @@ extern fn panic_fmt(args: &core::fmt::Arguments,
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
||||
#[lang = "eh_personality"] extern fn eh_personality() {}
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
|
||||
|
||||
@ -81,3 +81,55 @@ will let you do this:
|
||||
let p: Point = // ...
|
||||
let x: f64 = p + 2i32;
|
||||
```
|
||||
|
||||
# Using operator traits in generic structs
|
||||
|
||||
Now that we know how operator traits are defined, we can define our `HasArea`
|
||||
trait and `Square` struct from the [traits chapter][traits] more generically:
|
||||
|
||||
[traits]: traits.html
|
||||
|
||||
```rust
|
||||
use std::ops::Mul;
|
||||
|
||||
trait HasArea<T> {
|
||||
fn area(&self) -> T;
|
||||
}
|
||||
|
||||
struct Square<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
side: T,
|
||||
}
|
||||
|
||||
impl<T> HasArea<T> for Square<T>
|
||||
where T: Mul<Output=T> + Copy {
|
||||
fn area(&self) -> T {
|
||||
self.side * self.side
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let s = Square {
|
||||
x: 0.0f64,
|
||||
y: 0.0f64,
|
||||
side: 12.0f64,
|
||||
};
|
||||
|
||||
println!("Area of s: {}", s.area());
|
||||
}
|
||||
```
|
||||
|
||||
For `HasArea` and `Square`, we just declare a type parameter `T` and replace
|
||||
`f64` with it. The `impl` needs more involved modifications:
|
||||
|
||||
```ignore
|
||||
impl<T> HasArea<T> for Square<T>
|
||||
where T: Mul<Output=T> + Copy { ... }
|
||||
```
|
||||
|
||||
The `area` method requires that we can multiply the sides, so we declare that
|
||||
type `T` must implement `std::ops::Mul`. Like `Add`, mentioned above, `Mul`
|
||||
itself takes an `Output` parameter: since we know that numbers don't change
|
||||
type when multiplied, we also set it to `T`. `T` must also support copying, so
|
||||
Rust doesn't try to move `self.side` into the return value.
|
||||
|
||||
@ -39,203 +39,6 @@ match x {
|
||||
|
||||
This prints `one or two`.
|
||||
|
||||
# Ranges
|
||||
|
||||
You can match a range of values with `...`:
|
||||
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
1 ... 5 => println!("one through five"),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `one through five`.
|
||||
|
||||
Ranges are mostly used with integers and `char`s:
|
||||
|
||||
```rust
|
||||
let x = '💅';
|
||||
|
||||
match x {
|
||||
'a' ... 'j' => println!("early letter"),
|
||||
'k' ... 'z' => println!("late letter"),
|
||||
_ => println!("something else"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `something else`.
|
||||
|
||||
# Bindings
|
||||
|
||||
You can bind values to names with `@`:
|
||||
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
e @ 1 ... 5 => println!("got a range element {}", e),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `got a range element 1`. This is useful when you want to
|
||||
do a complicated match of part of a data structure:
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
let name = "Steve".to_string();
|
||||
let mut x: Option<Person> = Some(Person { name: Some(name) });
|
||||
match x {
|
||||
Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a),
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Some("Steve")`: We’ve bound the inner `name` to `a`.
|
||||
|
||||
If you use `@` with `|`, you need to make sure the name is bound in each part
|
||||
of the pattern:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
# Ignoring bindings
|
||||
|
||||
You can use `_` in a pattern to disregard the type and value.
|
||||
For example, here’s a `match` against a `Result<T, E>`:
|
||||
|
||||
```rust
|
||||
# let some_value: Result<i32, &'static str> = Err("There was an error");
|
||||
match some_value {
|
||||
Ok(value) => println!("got a value: {}", value),
|
||||
Err(_) => println!("an error occurred"),
|
||||
}
|
||||
```
|
||||
|
||||
In the first arm, we bind the value inside the `Ok` variant to `value`. But
|
||||
in the `Err` arm, we use `_` to disregard the specific error, and just print
|
||||
a general error message.
|
||||
|
||||
`_` is valid in any pattern that creates a binding. This can be useful to
|
||||
ignore parts of a larger structure:
|
||||
|
||||
```rust
|
||||
fn coordinate() -> (i32, i32, i32) {
|
||||
// generate and return some sort of triple tuple
|
||||
# (1, 2, 3)
|
||||
}
|
||||
|
||||
let (x, _, z) = coordinate();
|
||||
```
|
||||
|
||||
Here, we bind the first and last element of the tuple to `x` and `z`, but
|
||||
ignore the middle element.
|
||||
|
||||
Similarly, you can use `..` in a pattern to disregard multiple values.
|
||||
|
||||
```rust
|
||||
enum OptionalTuple {
|
||||
Value(i32, i32, i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalTuple::Value(5, -2, 3);
|
||||
|
||||
match x {
|
||||
OptionalTuple::Value(..) => println!("Got a tuple!"),
|
||||
OptionalTuple::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got a tuple!`.
|
||||
|
||||
# Guards
|
||||
|
||||
You can introduce ‘match guards’ with `if`:
|
||||
|
||||
```rust
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalInt::Value(5);
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
|
||||
OptionalInt::Value(..) => println!("Got an int!"),
|
||||
OptionalInt::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got an int!`.
|
||||
|
||||
If you’re using `if` with multiple patterns, the `if` applies to both sides:
|
||||
|
||||
```rust
|
||||
let x = 4;
|
||||
let y = false;
|
||||
|
||||
match x {
|
||||
4 | 5 if y => println!("yes"),
|
||||
_ => println!("no"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
|
||||
just the `5`, In other words, the the precedence of `if` behaves like this:
|
||||
|
||||
```text
|
||||
(4 | 5) if y => ...
|
||||
```
|
||||
|
||||
not this:
|
||||
|
||||
```text
|
||||
4 | (5 if y) => ...
|
||||
```
|
||||
|
||||
# ref and ref mut
|
||||
|
||||
If you want to get a [reference][ref], use the `ref` keyword:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
ref r => println!("Got a reference to {}", r),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got a reference to 5`.
|
||||
|
||||
[ref]: references-and-borrowing.html
|
||||
|
||||
Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
|
||||
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
||||
reference, `ref mut` will work in the same way:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
|
||||
match x {
|
||||
ref mut mr => println!("Got a mutable reference to {}", mr),
|
||||
}
|
||||
```
|
||||
|
||||
# Destructuring
|
||||
|
||||
If you have a compound data type, like a [`struct`][struct], you can destructure it
|
||||
@ -311,6 +114,203 @@ This ‘destructuring’ behavior works on any compound data type, like
|
||||
[tuples]: primitive-types.html#tuples
|
||||
[enums]: enums.html
|
||||
|
||||
# Ignoring bindings
|
||||
|
||||
You can use `_` in a pattern to disregard the type and value.
|
||||
For example, here’s a `match` against a `Result<T, E>`:
|
||||
|
||||
```rust
|
||||
# let some_value: Result<i32, &'static str> = Err("There was an error");
|
||||
match some_value {
|
||||
Ok(value) => println!("got a value: {}", value),
|
||||
Err(_) => println!("an error occurred"),
|
||||
}
|
||||
```
|
||||
|
||||
In the first arm, we bind the value inside the `Ok` variant to `value`. But
|
||||
in the `Err` arm, we use `_` to disregard the specific error, and just print
|
||||
a general error message.
|
||||
|
||||
`_` is valid in any pattern that creates a binding. This can be useful to
|
||||
ignore parts of a larger structure:
|
||||
|
||||
```rust
|
||||
fn coordinate() -> (i32, i32, i32) {
|
||||
// generate and return some sort of triple tuple
|
||||
# (1, 2, 3)
|
||||
}
|
||||
|
||||
let (x, _, z) = coordinate();
|
||||
```
|
||||
|
||||
Here, we bind the first and last element of the tuple to `x` and `z`, but
|
||||
ignore the middle element.
|
||||
|
||||
Similarly, you can use `..` in a pattern to disregard multiple values.
|
||||
|
||||
```rust
|
||||
enum OptionalTuple {
|
||||
Value(i32, i32, i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalTuple::Value(5, -2, 3);
|
||||
|
||||
match x {
|
||||
OptionalTuple::Value(..) => println!("Got a tuple!"),
|
||||
OptionalTuple::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got a tuple!`.
|
||||
|
||||
# ref and ref mut
|
||||
|
||||
If you want to get a [reference][ref], use the `ref` keyword:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
ref r => println!("Got a reference to {}", r),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got a reference to 5`.
|
||||
|
||||
[ref]: references-and-borrowing.html
|
||||
|
||||
Here, the `r` inside the `match` has the type `&i32`. In other words, the `ref`
|
||||
keyword _creates_ a reference, for use in the pattern. If you need a mutable
|
||||
reference, `ref mut` will work in the same way:
|
||||
|
||||
```rust
|
||||
let mut x = 5;
|
||||
|
||||
match x {
|
||||
ref mut mr => println!("Got a mutable reference to {}", mr),
|
||||
}
|
||||
```
|
||||
|
||||
# Ranges
|
||||
|
||||
You can match a range of values with `...`:
|
||||
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
1 ... 5 => println!("one through five"),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `one through five`.
|
||||
|
||||
Ranges are mostly used with integers and `char`s:
|
||||
|
||||
```rust
|
||||
let x = '💅';
|
||||
|
||||
match x {
|
||||
'a' ... 'j' => println!("early letter"),
|
||||
'k' ... 'z' => println!("late letter"),
|
||||
_ => println!("something else"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `something else`.
|
||||
|
||||
# Bindings
|
||||
|
||||
You can bind values to names with `@`:
|
||||
|
||||
```rust
|
||||
let x = 1;
|
||||
|
||||
match x {
|
||||
e @ 1 ... 5 => println!("got a range element {}", e),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `got a range element 1`. This is useful when you want to
|
||||
do a complicated match of part of a data structure:
|
||||
|
||||
```rust
|
||||
#[derive(Debug)]
|
||||
struct Person {
|
||||
name: Option<String>,
|
||||
}
|
||||
|
||||
let name = "Steve".to_string();
|
||||
let mut x: Option<Person> = Some(Person { name: Some(name) });
|
||||
match x {
|
||||
Some(Person { name: ref a @ Some(_), .. }) => println!("{:?}", a),
|
||||
_ => {}
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Some("Steve")`: we’ve bound the inner `name` to `a`.
|
||||
|
||||
If you use `@` with `|`, you need to make sure the name is bound in each part
|
||||
of the pattern:
|
||||
|
||||
```rust
|
||||
let x = 5;
|
||||
|
||||
match x {
|
||||
e @ 1 ... 5 | e @ 8 ... 10 => println!("got a range element {}", e),
|
||||
_ => println!("anything"),
|
||||
}
|
||||
```
|
||||
|
||||
# Guards
|
||||
|
||||
You can introduce ‘match guards’ with `if`:
|
||||
|
||||
```rust
|
||||
enum OptionalInt {
|
||||
Value(i32),
|
||||
Missing,
|
||||
}
|
||||
|
||||
let x = OptionalInt::Value(5);
|
||||
|
||||
match x {
|
||||
OptionalInt::Value(i) if i > 5 => println!("Got an int bigger than five!"),
|
||||
OptionalInt::Value(..) => println!("Got an int!"),
|
||||
OptionalInt::Missing => println!("No such luck."),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `Got an int!`.
|
||||
|
||||
If you’re using `if` with multiple patterns, the `if` applies to both sides:
|
||||
|
||||
```rust
|
||||
let x = 4;
|
||||
let y = false;
|
||||
|
||||
match x {
|
||||
4 | 5 if y => println!("yes"),
|
||||
_ => println!("no"),
|
||||
}
|
||||
```
|
||||
|
||||
This prints `no`, because the `if` applies to the whole of `4 | 5`, and not to
|
||||
just the `5`, In other words, the the precedence of `if` behaves like this:
|
||||
|
||||
```text
|
||||
(4 | 5) if y => ...
|
||||
```
|
||||
|
||||
not this:
|
||||
|
||||
```text
|
||||
4 | (5 if y) => ...
|
||||
```
|
||||
|
||||
# Mix and Match
|
||||
|
||||
Whew! That’s a lot of different ways to match things, and they can all be
|
||||
|
||||
@ -125,6 +125,10 @@ This will print `6`. We make `y` a mutable reference to `x`, then add one to
|
||||
the thing `y` points at. You’ll notice that `x` had to be marked `mut` as well,
|
||||
if it wasn’t, we couldn’t take a mutable borrow to an immutable value.
|
||||
|
||||
You'll also notice we added an asterisk (`*`) in front of `y`, making it `*y`,
|
||||
this is because `y` is an `&mut` reference. You'll also need to use them for
|
||||
accessing the contents of a reference as well.
|
||||
|
||||
Otherwise, `&mut` references are just like references. There _is_ a large
|
||||
difference between the two, and how they interact, though. You can tell
|
||||
something is fishy in the above example, because we need that extra scope, with
|
||||
@ -155,8 +159,8 @@ First, any borrow must last for a scope no greater than that of the owner.
|
||||
Second, you may have one or the other of these two kinds of borrows, but not
|
||||
both at the same time:
|
||||
|
||||
* one or more references (`&T`) to a resource.
|
||||
* exactly one mutable reference (`&mut T`)
|
||||
* one or more references (`&T`) to a resource,
|
||||
* exactly one mutable reference (`&mut T`).
|
||||
|
||||
|
||||
You may notice that this is very similar, though not exactly the same as,
|
||||
@ -294,8 +298,8 @@ We can’t modify `v` because it’s borrowed by the loop.
|
||||
|
||||
### use after free
|
||||
|
||||
References must live as long as the resource they refer to. Rust will check the
|
||||
scopes of your references to ensure that this is true.
|
||||
References must not live longer than the resource they refer to. Rust will
|
||||
check the scopes of your references to ensure that this is true.
|
||||
|
||||
If Rust didn’t check this property, we could accidentally use a reference
|
||||
which was invalid. For example:
|
||||
|
||||
@ -111,7 +111,7 @@ fn process() {
|
||||
for _ in (0..5_000_000) {
|
||||
x += 1
|
||||
}
|
||||
x
|
||||
x
|
||||
})
|
||||
}).collect();
|
||||
|
||||
@ -217,6 +217,17 @@ And finally, we can try running it:
|
||||
|
||||
```bash
|
||||
$ ruby embed.rb
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
Thread finished with count=5000000
|
||||
done!
|
||||
done!
|
||||
$
|
||||
```
|
||||
|
||||
@ -115,7 +115,7 @@ You can get something similar to an index like this:
|
||||
let dog = hachiko.chars().nth(1); // kinda like hachiko[1]
|
||||
```
|
||||
|
||||
This emphasizes that we have to go through the whole list of `chars`.
|
||||
This emphasizes that we have to walk from the beginning of the list of `chars`.
|
||||
|
||||
## Slicing
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
% Structs
|
||||
|
||||
Structs are a way of creating more complex data types. For example, if we were
|
||||
`struct`s are a way of creating more complex data types. For example, if we were
|
||||
doing calculations involving coordinates in 2D space, we would need both an `x`
|
||||
and a `y` value:
|
||||
|
||||
@ -9,7 +9,7 @@ let origin_x = 0;
|
||||
let origin_y = 0;
|
||||
```
|
||||
|
||||
A struct lets us combine these two into a single, unified datatype:
|
||||
A `struct` lets us combine these two into a single, unified datatype:
|
||||
|
||||
```rust
|
||||
struct Point {
|
||||
@ -28,14 +28,14 @@ There’s a lot going on here, so let’s break it down. We declare a `struct` w
|
||||
the `struct` keyword, and then with a name. By convention, `struct`s begin with
|
||||
a capital letter and are camel cased: `PointInSpace`, not `Point_In_Space`.
|
||||
|
||||
We can create an instance of our struct via `let`, as usual, but we use a `key:
|
||||
We can create an instance of our `struct` via `let`, as usual, but we use a `key:
|
||||
value` style syntax to set each field. The order doesn’t need to be the same as
|
||||
in the original declaration.
|
||||
|
||||
Finally, because fields have names, we can access the field through dot
|
||||
notation: `origin.x`.
|
||||
|
||||
The values in structs are immutable by default, like other bindings in Rust.
|
||||
The values in `struct`s are immutable by default, like other bindings in Rust.
|
||||
Use `mut` to make them mutable:
|
||||
|
||||
```rust
|
||||
@ -91,7 +91,7 @@ fn main() {
|
||||
# Update syntax
|
||||
|
||||
A `struct` can include `..` to indicate that you want to use a copy of some
|
||||
other struct for some of the values. For example:
|
||||
other `struct` for some of the values. For example:
|
||||
|
||||
```rust
|
||||
struct Point3d {
|
||||
@ -121,7 +121,7 @@ let point = Point3d { z: 1, x: 2, .. origin };
|
||||
# Tuple structs
|
||||
|
||||
Rust has another data type that’s like a hybrid between a [tuple][tuple] and a
|
||||
struct, called a ‘tuple struct’. Tuple structs have a name, but
|
||||
`struct`, called a ‘tuple struct’. Tuple structs have a name, but
|
||||
their fields don’t:
|
||||
|
||||
```rust
|
||||
@ -140,7 +140,7 @@ let black = Color(0, 0, 0);
|
||||
let origin = Point(0, 0, 0);
|
||||
```
|
||||
|
||||
It is almost always better to use a struct than a tuple struct. We would write
|
||||
It is almost always better to use a `struct` than a tuple struct. We would write
|
||||
`Color` and `Point` like this instead:
|
||||
|
||||
```rust
|
||||
@ -158,7 +158,7 @@ struct Point {
|
||||
```
|
||||
|
||||
Now, we have actual names, rather than positions. Good names are important,
|
||||
and with a struct, we have actual names.
|
||||
and with a `struct`, we have actual names.
|
||||
|
||||
There _is_ one case when a tuple struct is very useful, though, and that’s a
|
||||
tuple struct with only one element. We call this the ‘newtype’ pattern, because
|
||||
@ -180,13 +180,13 @@ destructuring `let`, just as with regular tuples. In this case, the
|
||||
|
||||
# Unit-like structs
|
||||
|
||||
You can define a struct with no members at all:
|
||||
You can define a `struct` with no members at all:
|
||||
|
||||
```rust
|
||||
struct Electron;
|
||||
```
|
||||
|
||||
Such a struct is called ‘unit-like’ because it resembles the empty
|
||||
Such a `struct` is called ‘unit-like’ because it resembles the empty
|
||||
tuple, `()`, sometimes called ‘unit’. Like a tuple struct, it defines a
|
||||
new type.
|
||||
|
||||
@ -195,6 +195,6 @@ marker type), but in combination with other features, it can become
|
||||
useful. For instance, a library may ask you to create a structure that
|
||||
implements a certain [trait][trait] to handle events. If you don’t have
|
||||
any data you need to store in the structure, you can just create a
|
||||
unit-like struct.
|
||||
unit-like `struct`.
|
||||
|
||||
[trait]: traits.html
|
||||
|
||||
@ -120,13 +120,26 @@ And that's reflected in the summary line:
|
||||
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
We also get a non-zero status code:
|
||||
We also get a non-zero status code. We can use `$?` on OS X and Linux:
|
||||
|
||||
```bash
|
||||
$ echo $?
|
||||
101
|
||||
```
|
||||
|
||||
On Windows, if you’re using `cmd`:
|
||||
|
||||
```bash
|
||||
> echo %ERRORLEVEL%
|
||||
```
|
||||
|
||||
And if you’re using PowerShell:
|
||||
|
||||
```bash
|
||||
> echo $LASTEXITCODE # the code itself
|
||||
> echo $? # a boolean, fail or succeed
|
||||
```
|
||||
|
||||
This is useful if you want to integrate `cargo test` into other tooling.
|
||||
|
||||
We can invert our test's failure with another attribute: `should_panic`:
|
||||
@ -219,6 +232,66 @@ fn it_works() {
|
||||
This is a very common use of `assert_eq!`: call some function with
|
||||
some known arguments and compare it to the expected output.
|
||||
|
||||
# The `ignore` attribute
|
||||
|
||||
Sometimes a few specific tests can be very time-consuming to execute. These
|
||||
can be disabled by default by using the `ignore` attribute:
|
||||
|
||||
```rust
|
||||
#[test]
|
||||
fn it_works() {
|
||||
assert_eq!(4, add_two(2));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn expensive_test() {
|
||||
// code that takes an hour to run
|
||||
}
|
||||
```
|
||||
|
||||
Now we run our tests and see that `it_works` is run, but `expensive_test` is
|
||||
not:
|
||||
|
||||
```bash
|
||||
$ cargo test
|
||||
Compiling adder v0.0.1 (file:///home/you/projects/adder)
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 2 tests
|
||||
test expensive_test ... ignored
|
||||
test it_works ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured
|
||||
|
||||
Doc-tests adder
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
The expensive tests can be run explicitly using `cargo test -- --ignored`:
|
||||
|
||||
```bash
|
||||
$ cargo test -- --ignored
|
||||
Running target/adder-91b3e234d4ed382a
|
||||
|
||||
running 1 test
|
||||
test expensive_test ... ok
|
||||
|
||||
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
|
||||
|
||||
Doc-tests adder
|
||||
|
||||
running 0 tests
|
||||
|
||||
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
|
||||
```
|
||||
|
||||
The `--ignored` argument is an argument to the test binary, and not to cargo,
|
||||
which is why the command is `cargo test -- --ignored`.
|
||||
|
||||
# The `tests` module
|
||||
|
||||
There is one way in which our existing example is not idiomatic: it's
|
||||
@ -355,8 +428,8 @@ Let's finally check out that third section: documentation tests.
|
||||
Nothing is better than documentation with examples. Nothing is worse than
|
||||
examples that don't actually work, because the code has changed since the
|
||||
documentation has been written. To this end, Rust supports automatically
|
||||
running examples in your documentation. Here's a fleshed-out `src/lib.rs`
|
||||
with examples:
|
||||
running examples in your documentation (**note:** this only works in library
|
||||
crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples:
|
||||
|
||||
```rust,ignore
|
||||
//! The `adder` crate provides functions that add numbers to other numbers.
|
||||
|
||||
@ -38,7 +38,7 @@ local variables and some other information. This is called a ‘stack frame’,
|
||||
for the purpose of this tutorial, we’re going to ignore the extra information
|
||||
and just consider the local variables we’re allocating. So in this case, when
|
||||
`main()` is run, we’ll allocate a single 32-bit integer for our stack frame.
|
||||
This is automatically handled for you, as you can see, we didn’t have to write
|
||||
This is automatically handled for you, as you can see; we didn’t have to write
|
||||
any special Rust code or anything.
|
||||
|
||||
When the function is over, its stack frame gets deallocated. This happens
|
||||
@ -51,7 +51,7 @@ we’ll throw them all away at the same time as well, we can get rid of it very
|
||||
fast too.
|
||||
|
||||
The downside is that we can’t keep values around if we need them for longer
|
||||
than a single function. We also haven’t talked about what that name, ‘stack’
|
||||
than a single function. We also haven’t talked about what the word, ‘stack’,
|
||||
means. To do that, we need a slightly more complicated example:
|
||||
|
||||
```rust
|
||||
@ -217,12 +217,12 @@ on the heap. The actual value of the box is a structure which has a pointer to
|
||||
it allocates some memory for the heap, and puts `5` there. The memory now looks
|
||||
like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | 2<sup>30</sup> |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | → 2<sup>30</sup> |
|
||||
|
||||
We have 2<sup>30</sup> in our hypothetical computer with 1GB of RAM. And since
|
||||
our stack grows from zero, the easiest place to allocate memory is from the
|
||||
@ -242,17 +242,17 @@ freed in any order, it can end up with ‘holes’. Here’s a diagram of the me
|
||||
layout of a program which has been running for a while now:
|
||||
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | |
|
||||
| (2<sup>30</sup>) - 2 | | |
|
||||
| (2<sup>30</sup>) - 3 | | 42 |
|
||||
| ... | ... | ... |
|
||||
| 3 | y | (2<sup>30</sup>) - 3 |
|
||||
| 2 | y | 42 |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | 2<sup>30</sup> |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 5 |
|
||||
| (2<sup>30</sup>) - 1 | | |
|
||||
| (2<sup>30</sup>) - 2 | | |
|
||||
| (2<sup>30</sup>) - 3 | | 42 |
|
||||
| ... | ... | ... |
|
||||
| 3 | y | → (2<sup>30</sup>) - 3 |
|
||||
| 2 | y | 42 |
|
||||
| 1 | y | 42 |
|
||||
| 0 | x | → 2<sup>30</sup> |
|
||||
|
||||
In this case, we’ve allocated four things on the heap, but deallocated two of
|
||||
them. There’s a gap between 2<sup>30</sup> and (2<sup>30</sup>) - 3 which isn’t
|
||||
@ -304,22 +304,22 @@ fn main() {
|
||||
|
||||
When we enter `main()`, memory looks like this:
|
||||
|
||||
| Address | Name | Value |
|
||||
|---------|------|-------|
|
||||
| 1 | y | 0 |
|
||||
| 0 | x | 5 |
|
||||
| Address | Name | Value |
|
||||
|---------|------|--------|
|
||||
| 1 | y | → 0 |
|
||||
| 0 | x | 5 |
|
||||
|
||||
`x` is a plain old `5`, and `y` is a reference to `x`. So its value is the
|
||||
memory location that `x` lives at, which in this case is `0`.
|
||||
|
||||
What about when we call `foo()`, passing `y` as an argument?
|
||||
|
||||
| Address | Name | Value |
|
||||
|---------|------|-------|
|
||||
| 3 | z | 42 |
|
||||
| 2 | i | 0 |
|
||||
| 1 | y | 0 |
|
||||
| 0 | x | 5 |
|
||||
| Address | Name | Value |
|
||||
|---------|------|--------|
|
||||
| 3 | z | 42 |
|
||||
| 2 | i | → 0 |
|
||||
| 1 | y | → 0 |
|
||||
| 0 | x | 5 |
|
||||
|
||||
Stack frames aren’t just for local bindings, they’re for arguments too. So in
|
||||
this case, we need to have both `i`, our argument, and `z`, our local variable
|
||||
@ -366,29 +366,29 @@ fn main() {
|
||||
|
||||
First, we call `main()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a
|
||||
value pointing there.
|
||||
|
||||
Next, at the end of `main()`, `foo()` gets called:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|-----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup>|
|
||||
| 0 | h | 3 |
|
||||
|
||||
Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value
|
||||
as `j`, since that’s what we passed it in. It’s a pointer to the `0` address,
|
||||
@ -396,51 +396,51 @@ since `j` points at `h`.
|
||||
|
||||
Next, `foo()` calls `baz()`, passing `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
| 6 | f | 4 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 7 | g | 100 |
|
||||
| 6 | f | → 4 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s
|
||||
over, we get rid of its stack frame:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, `foo()` calls `bar()` with `x` and `z`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
We end up allocating another value on the heap, and so we have to subtract one
|
||||
from 2<sup>30</sup>. It’s easier to just write that than `1,073,741,823`. In any
|
||||
@ -448,70 +448,70 @@ case, we set up the variables as usual.
|
||||
|
||||
At the end of `bar()`, it calls `baz()`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 12 | g | 100 |
|
||||
| 11 | f | 9 |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 12 | g | 100 |
|
||||
| 11 | f | → 9 |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
With this, we’re at our deepest point! Whew! Congrats for following along this
|
||||
far.
|
||||
|
||||
After `baz()` is over, we get rid of `f` and `g`:
|
||||
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|----------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | 9 |
|
||||
| 9 | d | (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | 4 |
|
||||
| 6 | a | 0 |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|----------------------|------|------------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| (2<sup>30</sup>) - 1 | | 5 |
|
||||
| ... | ... | ... |
|
||||
| 10 | e | → 9 |
|
||||
| 9 | d | → (2<sup>30</sup>) - 1 |
|
||||
| 8 | c | 5 |
|
||||
| 7 | b | → 4 |
|
||||
| 6 | a | → 0 |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
Next, we return from `bar()`. `d` in this case is a `Box<T>`, so it also frees
|
||||
what it points to: (2<sup>30</sup>) - 1.
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | 0 |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 5 | z | → 4 |
|
||||
| 4 | y | 10 |
|
||||
| 3 | x | → 0 |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And after that, `foo()` returns:
|
||||
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|----------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | 0 |
|
||||
| 1 | i | 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
| Address | Name | Value |
|
||||
|-----------------|------|------------------|
|
||||
| 2<sup>30</sup> | | 20 |
|
||||
| ... | ... | ... |
|
||||
| 2 | j | → 0 |
|
||||
| 1 | i | → 2<sup>30</sup> |
|
||||
| 0 | h | 3 |
|
||||
|
||||
And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped,
|
||||
it will clean up the last of the heap too.
|
||||
@ -549,7 +549,7 @@ reuse.
|
||||
If you’d like to dive into this topic in greater detail, [this paper][wilson]
|
||||
is a great introduction.
|
||||
|
||||
[wilson]: http://www.cs.northwestern.edu/~pdinda/icsclass/doc/dsa.pdf
|
||||
[wilson]: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.143.4688
|
||||
|
||||
## Semantic impact
|
||||
|
||||
|
||||
@ -300,3 +300,41 @@ let y = TraitObject {
|
||||
// y.method();
|
||||
(y.vtable.method)(y.data);
|
||||
```
|
||||
|
||||
## Object Safety
|
||||
|
||||
Not every trait can be used to make a trait object. For example, vectors implement
|
||||
`Clone`, but if we try to make a trait object:
|
||||
|
||||
```ignore
|
||||
let v = vec![1, 2, 3];
|
||||
let o = &v as &Clone;
|
||||
```
|
||||
|
||||
We get an error:
|
||||
|
||||
```text
|
||||
error: cannot convert to a trait object because trait `core::clone::Clone` is not object-safe [E0038]
|
||||
let o = &v as &Clone;
|
||||
^~
|
||||
note: the trait cannot require that `Self : Sized`
|
||||
let o = &v as &Clone;
|
||||
^~
|
||||
```
|
||||
|
||||
The error says that `Clone` is not ‘object-safe’. Only traits that are
|
||||
object-safe can be made into trait objects. A trait is object-safe if both of
|
||||
these are true:
|
||||
|
||||
* the trait does not require that `Self: Sized`
|
||||
* all of its methods are object-safe
|
||||
|
||||
So what makes a method object-safe? Each method must require that `Self: Sized`
|
||||
or all of the following:
|
||||
|
||||
* must not have any type parameters
|
||||
* must not use `Self`
|
||||
|
||||
Whew! As we can see, almost all of these rules talk about `Self`. A good intuition
|
||||
is “except in special circumstances, if your trait’s method uses `Self`, it is not
|
||||
object-safe.”
|
||||
|
||||
@ -47,8 +47,11 @@ As you can see, the `trait` block looks very similar to the `impl` block,
|
||||
but we don’t define a body, just a type signature. When we `impl` a trait,
|
||||
we use `impl Trait for Item`, rather than just `impl Item`.
|
||||
|
||||
We can use traits to constrain our generics. Consider this function, which
|
||||
does not compile:
|
||||
## Traits bounds for generic functions
|
||||
|
||||
Traits are useful because they allow a type to make certain promises about its
|
||||
behavior. Generic functions can exploit this to constrain the types they
|
||||
accept. Consider this function, which does not compile:
|
||||
|
||||
```rust,ignore
|
||||
fn print_area<T>(shape: T) {
|
||||
@ -75,7 +78,7 @@ fn print_area<T: HasArea>(shape: T) {
|
||||
}
|
||||
```
|
||||
|
||||
The syntax `<T: HasArea>` means `any type that implements the HasArea trait`.
|
||||
The syntax `<T: HasArea>` means “any type that implements the `HasArea` trait.”
|
||||
Because traits define function type signatures, we can be sure that any type
|
||||
which implements `HasArea` will have an `.area()` method.
|
||||
|
||||
@ -152,6 +155,63 @@ We get a compile-time error:
|
||||
error: the trait `HasArea` is not implemented for the type `_` [E0277]
|
||||
```
|
||||
|
||||
## Traits bounds for generic structs
|
||||
|
||||
Your generic structs can also benefit from trait constraints. All you need to
|
||||
do is append the constraint when you declare type parameters. Here is a new
|
||||
type `Rectangle<T>` and its operation `is_square()`:
|
||||
|
||||
```rust
|
||||
struct Rectangle<T> {
|
||||
x: T,
|
||||
y: T,
|
||||
width: T,
|
||||
height: T,
|
||||
}
|
||||
|
||||
impl<T: PartialEq> Rectangle<T> {
|
||||
fn is_square(&self) -> bool {
|
||||
self.width == self.height
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let mut r = Rectangle {
|
||||
x: 0,
|
||||
y: 0,
|
||||
width: 47,
|
||||
height: 47,
|
||||
};
|
||||
|
||||
assert!(r.is_square());
|
||||
|
||||
r.height = 42;
|
||||
assert!(!r.is_square());
|
||||
}
|
||||
```
|
||||
|
||||
`is_square()` needs to check that the sides are equal, so the sides must be of
|
||||
a type that implements the [`core::cmp::PartialEq`][PartialEq] trait:
|
||||
|
||||
```ignore
|
||||
impl<T: PartialEq> Rectangle<T> { ... }
|
||||
```
|
||||
|
||||
Now, a rectangle can be defined in terms of any type that can be compared for
|
||||
equality.
|
||||
|
||||
[PartialEq]: ../core/cmp/trait.PartialEq.html
|
||||
|
||||
Here we defined a new struct `Rectangle` that accepts numbers of any
|
||||
precision—really, objects of pretty much any type—as long as they can be
|
||||
compared for equality. Could we do the same for our `HasArea` structs, `Square`
|
||||
and `Circle`? Yes, but they need multiplication, and to work with that we need
|
||||
to know more about [operator traits][operators-and-overloading].
|
||||
|
||||
[operators-and-overloading]: operators-and-overloading.html
|
||||
|
||||
# Rules for implementing traits
|
||||
|
||||
So far, we’ve only added trait implementations to structs, but you can
|
||||
implement a trait for any type. So technically, we _could_ implement `HasArea`
|
||||
for `i32`:
|
||||
@ -175,7 +235,7 @@ impl HasArea for i32 {
|
||||
It is considered poor style to implement methods on such primitive types, even
|
||||
though it is possible.
|
||||
|
||||
This may seem like the Wild West, but there are two other restrictions around
|
||||
This may seem like the Wild West, but there are two restrictions around
|
||||
implementing traits that prevent this from getting out of hand. The first is
|
||||
that if the trait isn’t defined in your scope, it doesn’t apply. Here’s an
|
||||
example: the standard library provides a [`Write`][write] trait which adds
|
||||
@ -330,7 +390,7 @@ fn normal<T: ConvertTo<i64>>(x: &T) -> i64 {
|
||||
|
||||
// can be called with T == i64
|
||||
fn inverse<T>() -> T
|
||||
// this is using ConvertTo as if it were "ConvertFrom<i32>"
|
||||
// this is using ConvertTo as if it were "ConvertTo<i64>"
|
||||
where i32: ConvertTo<T> {
|
||||
42.convert()
|
||||
}
|
||||
@ -340,10 +400,10 @@ This shows off the additional feature of `where` clauses: they allow bounds
|
||||
where the left-hand side is an arbitrary type (`i32` in this case), not just a
|
||||
plain type parameter (like `T`).
|
||||
|
||||
## Default methods
|
||||
# Default methods
|
||||
|
||||
There’s one last feature of traits we should cover: default methods. It’s
|
||||
easiest just to show an example:
|
||||
If you already know how a typical implementor will define a method, you can
|
||||
let your trait supply a default:
|
||||
|
||||
```rust
|
||||
trait Foo {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<div id="versioninfo">
|
||||
<img src="http://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt><br>
|
||||
<span class="white-sticker"><a href="http://rust-lang.org">Rust</a> VERSION</span><br>
|
||||
<a href="http://github.com/rust-lang/rust/commit/STAMP"
|
||||
<img src="https://www.rust-lang.org/logos/rust-logo-32x32-blk.png" width="32" height="32" alt><br>
|
||||
<span class="white-sticker"><a href="https://www.rust-lang.org">Rust</a> VERSION</span><br>
|
||||
<a href="https://github.com/rust-lang/rust/commit/STAMP"
|
||||
class="hash white-sticker">SHORT_HASH</a>
|
||||
</div>
|
||||
|
||||
134
src/etc/dec2flt_table.py
Normal file
134
src/etc/dec2flt_table.py
Normal file
@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env python2.7
|
||||
#
|
||||
# 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 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
"""
|
||||
Generate powers of ten using William Clinger's ``AlgorithmM`` for use in
|
||||
decimal to floating point conversions.
|
||||
|
||||
Specifically, computes and outputs (as Rust code) a table of 10^e for some
|
||||
range of exponents e. The output is one array of 64 bit significands and
|
||||
another array of corresponding base two exponents. The approximations are
|
||||
normalized and rounded perfectly, i.e., within 0.5 ULP of the true value.
|
||||
|
||||
The representation ([u64], [i16]) instead of the more natural [(u64, i16)]
|
||||
is used because (u64, i16) has a ton of padding which would make the table
|
||||
even larger, and it's already uncomfortably large (6 KiB).
|
||||
"""
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
from fractions import Fraction
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
N = 64 # Size of the significand field in bits
|
||||
MIN_SIG = 2 ** (N - 1)
|
||||
MAX_SIG = (2 ** N) - 1
|
||||
|
||||
|
||||
# Hand-rolled fp representation without arithmetic or any other operations.
|
||||
# The significand is normalized and always N bit, but the exponent is
|
||||
# unrestricted in range.
|
||||
Fp = namedtuple('Fp', 'sig exp')
|
||||
|
||||
|
||||
def algorithm_m(f, e):
|
||||
assert f > 0
|
||||
if e < 0:
|
||||
u = f
|
||||
v = 10 ** abs(e)
|
||||
else:
|
||||
u = f * 10 ** e
|
||||
v = 1
|
||||
k = 0
|
||||
x = u // v
|
||||
while True:
|
||||
if x < MIN_SIG:
|
||||
u <<= 1
|
||||
k -= 1
|
||||
elif x >= MAX_SIG:
|
||||
v <<= 1
|
||||
k += 1
|
||||
else:
|
||||
break
|
||||
x = u // v
|
||||
return ratio_to_float(u, v, k)
|
||||
|
||||
|
||||
def ratio_to_float(u, v, k):
|
||||
q, r = divmod(u, v)
|
||||
v_r = v - r
|
||||
z = Fp(q, k)
|
||||
if r < v_r:
|
||||
return z
|
||||
elif r > v_r:
|
||||
return next_float(z)
|
||||
elif q % 2 == 0:
|
||||
return z
|
||||
else:
|
||||
return next_float(z)
|
||||
|
||||
|
||||
def next_float(z):
|
||||
if z.sig == MAX_SIG:
|
||||
return Fp(MIN_SIG, z.exp + 1)
|
||||
else:
|
||||
return Fp(z.sig + 1, z.exp)
|
||||
|
||||
|
||||
def error(f, e, z):
|
||||
decimal = f * Fraction(10) ** e
|
||||
binary = z.sig * Fraction(2) ** z.exp
|
||||
abs_err = abs(decimal - binary)
|
||||
# The unit in the last place has value z.exp
|
||||
ulp_err = abs_err / Fraction(2) ** z.exp
|
||||
return float(ulp_err)
|
||||
|
||||
LICENSE = """
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
"""
|
||||
|
||||
def main():
|
||||
MIN_E = -305
|
||||
MAX_E = 305
|
||||
e_range = range(MIN_E, MAX_E+1)
|
||||
powers = []
|
||||
for e in e_range:
|
||||
z = algorithm_m(1, e)
|
||||
err = error(1, e, z)
|
||||
assert err < 0.5
|
||||
powers.append(z)
|
||||
typ = "([u64; {0}], [i16; {0}])".format(len(e_range))
|
||||
print(LICENSE.strip())
|
||||
print("// Table of approximations of powers of ten.")
|
||||
print("// DO NOT MODIFY: Generated by a src/etc/dec2flt_table.py")
|
||||
print("pub const MIN_E: i16 = {};".format(MIN_E))
|
||||
print("pub const MAX_E: i16 = {};".format(MAX_E))
|
||||
print()
|
||||
print("pub const POWERS: ", typ, " = ([", sep='')
|
||||
for z in powers:
|
||||
print(" 0x{:x},".format(z.sig))
|
||||
print("], [")
|
||||
for z in powers:
|
||||
print(" {},".format(z.exp))
|
||||
print("]);")
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@ -47,20 +47,24 @@ with open(feature_gate_source, 'r') as f:
|
||||
is_feature_line = True
|
||||
|
||||
if is_feature_line:
|
||||
line = line.replace("(", "").replace("),", "").replace(")", "")
|
||||
# turn ` ("foo", "1.0.0", Some(10), Active)` into
|
||||
# `"foo", "1.0.0", Some(10), Active`
|
||||
line = line.strip(' ,()')
|
||||
parts = line.split(",")
|
||||
if len(parts) != 3:
|
||||
if len(parts) != 4:
|
||||
print("error: unexpected number of components in line: " + original_line)
|
||||
sys.exit(1)
|
||||
feature_name = parts[0].strip().replace('"', "")
|
||||
since = parts[1].strip().replace('"', "")
|
||||
status = parts[2].strip()
|
||||
issue = parts[2].strip()
|
||||
status = parts[3].strip()
|
||||
assert len(feature_name) > 0
|
||||
assert len(since) > 0
|
||||
assert len(issue) > 0
|
||||
assert len(status) > 0
|
||||
|
||||
language_feature_names += [feature_name]
|
||||
language_features += [(feature_name, since, status)]
|
||||
language_features += [(feature_name, since, issue, status)]
|
||||
|
||||
assert len(language_features) > 0
|
||||
|
||||
@ -158,7 +162,7 @@ for f in language_features:
|
||||
status = "unstable"
|
||||
stable_since = None
|
||||
|
||||
if f[2] == "Accepted":
|
||||
if f[3] == "Accepted":
|
||||
status = "stable"
|
||||
if status == "stable":
|
||||
stable_since = f[1]
|
||||
|
||||
@ -45,7 +45,7 @@ def make_win_dist(rust_root, gcc_root, target_triple):
|
||||
elif key == "libraries":
|
||||
lib_path.extend(val.lstrip(' =').split(';'))
|
||||
|
||||
target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe", "windres.exe"]
|
||||
target_tools = ["gcc.exe", "ld.exe", "ar.exe", "dlltool.exe"]
|
||||
|
||||
rustc_dlls = ["libstdc++-6.dll"]
|
||||
if target_triple.startswith("i686-"):
|
||||
|
||||
@ -41,14 +41,14 @@ def convert_path_spec(name, value):
|
||||
make = sys.argv[2]
|
||||
putenv('RUSTC', os.path.abspath(sys.argv[3]))
|
||||
putenv('TMPDIR', os.path.abspath(sys.argv[4]))
|
||||
putenv('CC', sys.argv[5])
|
||||
putenv('RUSTDOC', os.path.abspath(sys.argv[6]))
|
||||
filt = sys.argv[7]
|
||||
putenv('LD_LIB_PATH_ENVVAR', sys.argv[8])
|
||||
putenv('HOST_RPATH_DIR', os.path.abspath(sys.argv[9]))
|
||||
putenv('TARGET_RPATH_DIR', os.path.abspath(sys.argv[10]))
|
||||
putenv('RUST_BUILD_STAGE', sys.argv[11])
|
||||
putenv('S', os.path.abspath(sys.argv[12]))
|
||||
putenv('CC', sys.argv[5] + ' ' + sys.argv[6])
|
||||
putenv('RUSTDOC', os.path.abspath(sys.argv[7]))
|
||||
filt = sys.argv[8]
|
||||
putenv('LD_LIB_PATH_ENVVAR', sys.argv[9])
|
||||
putenv('HOST_RPATH_DIR', os.path.abspath(sys.argv[10]))
|
||||
putenv('TARGET_RPATH_DIR', os.path.abspath(sys.argv[11]))
|
||||
putenv('RUST_BUILD_STAGE', sys.argv[12])
|
||||
putenv('S', os.path.abspath(sys.argv[13]))
|
||||
putenv('PYTHON', sys.executable)
|
||||
|
||||
if filt not in sys.argv[1]:
|
||||
|
||||
592
src/etc/platform-intrinsics/aarch64.json
Normal file
592
src/etc/platform-intrinsics/aarch64.json
Normal file
@ -0,0 +1,592 @@
|
||||
{
|
||||
"platform": "aarch64",
|
||||
"intrinsic_prefix": "aarch64_v",
|
||||
"llvm_prefix": "llvm.aarch64.neon.",
|
||||
"number_info": {
|
||||
"signed": {
|
||||
"kind": "s",
|
||||
"data_type": { "pattern": "s{bitwidth}" }
|
||||
},
|
||||
"unsigned": {
|
||||
"kind": "u",
|
||||
"data_type": { "pattern": "u{bitwidth}" }
|
||||
},
|
||||
"float": {
|
||||
"kind": "f",
|
||||
"data_type": { "pattern": "f{bitwidth}" }
|
||||
}
|
||||
},
|
||||
"width_info": {
|
||||
"64": { "width": "" },
|
||||
"128": { "width": "q" }
|
||||
},
|
||||
"intrinsics": [
|
||||
{
|
||||
"intrinsic": "hadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}hadd.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rhadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}rhadd.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}qadd.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "uqadd_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "suqadd.{0.llvm_name}",
|
||||
"ret": "s(8-64)",
|
||||
"args": ["0", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sqadd_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "usqadd.{0.llvm_name}",
|
||||
"ret": "u(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "raddhn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "raddhn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "fmulx{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "fmulx.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "fma{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.fma.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qdmulh{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqdmulh.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrdmulh{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqrdmulh.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "mull_{1.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}mull.{0.llvm_name}",
|
||||
"ret": "i(16-64)",
|
||||
"args": ["0n", "0n"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qdmull{0.width}_{1.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "sqdmull.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0n", "0n"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "hsub{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}hsub.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qsub{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}qsub.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsubhn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "rsubhn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abd{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}abd.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f(32-64)"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "max{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}max.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f(32-64)"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "min{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}min.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f(32-64)"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "maxnm{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}maxnm.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "minnm{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}minnm.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "shl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}shl.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}qshl.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}rshl.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}qrshl.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshrun_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "sqshrun.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshrun_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "sqrshrun.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "{0.kind}qshrn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "rshrn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "{0.kind}qrshrn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sri{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "vsri.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sli{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "vsli.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "vqmovn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "{0.kind}qxtn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abs{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "abs.{0.llvm_name}",
|
||||
"ret": "s(8-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abs{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.fabs.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qabs{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "sqabs.{0.llvm_name}",
|
||||
"ret": "s(8-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qneg{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqneg.{0.llvm_name}",
|
||||
"ret": "s(8-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "clz{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.ctlz.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "cls{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "cls.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "cnt{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.ctpop.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "recpe{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}recpe.{0.llvm_name}",
|
||||
"ret": ["u32","f(32-64)"],
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "recps{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "frecps.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sqrt{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.sqrt.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsqrte{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}rsqrte.{0.llvm_name}",
|
||||
"ret": ["u32","f(32-64)"],
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsqrts{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "frsqrts.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rbit{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "rbit.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld2{0[0].width}_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld2.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);2]","[f(32-64);2]"],
|
||||
"args": ["0.0SPc/0.0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld3{0[0].width}_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld3.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);3]","[f(32-64);3]"],
|
||||
"args": ["0.0SPc/0.0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld4{0[0].width}_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld4.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);4]","[f(32-64);4]"],
|
||||
"args": ["0.0SPc/0.0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld2{0[0].width}_dup_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld2.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);2]","[f(32-64);2]"],
|
||||
"args": ["0.0SPc"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld3{0[0].width}_dup_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld3.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);3]","[f(32-64);3]"],
|
||||
"args": ["0.0SPc"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "ld4{0[0].width}_dup_{0[0].data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "ld4.{0[0].llvm_name}.{1.llvm_name}",
|
||||
"ret": ["[i(8-64);4]","[f(32-64);4]"],
|
||||
"args": ["0.0SPc"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "padd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "addp.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "padd{0.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "addp.{0.llvm_name}",
|
||||
"ret": ["i64","f64"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "paddl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}addlp.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "i(16-64)",
|
||||
"args": ["0dn"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmax{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}maxp.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmax{0.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}maxp.{0.llvm_name}",
|
||||
"ret": ["i64","f64"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmin{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}minp.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmin{0.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}minp.{0.llvm_name}",
|
||||
"ret": ["i64","f64"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmaxnm{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}maxnmp.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmaxnm{0.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}maxnmp.{0.llvm_name}",
|
||||
"ret": ["i64","f64"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pminnm{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}minnmp.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pminnm{0.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}minnmp.{0.llvm_name}",
|
||||
"ret": "f64",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "addv{1.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}addv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": ["I(8-32)","F32"],
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "addv{1.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}addv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": ["I64","F64"],
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "addlv{1.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}addlv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "I(16-64)",
|
||||
"args": ["0vdn"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "maxv{1.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}maxv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": ["I(8-32)","F32"],
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "maxv{1.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}maxv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F64",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "minv{1.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}minv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": ["I(8-32)","F32"],
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "minv{1.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}minv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F64",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "maxnmv{1.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}maxnmv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F32",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "maxnmv{1.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}maxnmv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F64",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "minnmv{1.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "{0.kind}minnmv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F32",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "minnmv{1.width}_{0.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "{0.kind}minnmv.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "F64",
|
||||
"args": ["0v"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbl1{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbl1.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0x128", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbx1{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbx1.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0", "0x128", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbl2{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbl2.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["(0x128,0x128)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbx2{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbx2.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["(0x128,0x128)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbl3{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbl3.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["(0x128,0x128,0x128)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbx3{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbx3.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0", "(0x128,0x128,0x128)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbl4{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbl4.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["(0x128,0x128,0x128,0x128)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qtbx4{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "tbx4.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0", "(0x128,0x128,0x128,0x128)f", "0u"]
|
||||
}
|
||||
]
|
||||
}
|
||||
396
src/etc/platform-intrinsics/arm.json
Normal file
396
src/etc/platform-intrinsics/arm.json
Normal file
@ -0,0 +1,396 @@
|
||||
{
|
||||
"platform": "arm",
|
||||
"intrinsic_prefix": "arm_v",
|
||||
"llvm_prefix": "llvm.neon.v",
|
||||
"number_info": {
|
||||
"signed": {
|
||||
"kind": "s",
|
||||
"data_type": { "pattern": "s{bitwidth}" }
|
||||
},
|
||||
"unsigned": {
|
||||
"kind": "u",
|
||||
"data_type": { "pattern": "u{bitwidth}" }
|
||||
},
|
||||
"float": {
|
||||
"kind": "f",
|
||||
"data_type": { "pattern": "f{bitwidth}" }
|
||||
}
|
||||
},
|
||||
"width_info": {
|
||||
"64": { "width": "" },
|
||||
"128": { "width": "q" }
|
||||
},
|
||||
"intrinsics": [
|
||||
{
|
||||
"intrinsic": "hadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "hadd{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rhadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "rhadd{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qadd{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "qadd{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "raddhn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "raddhn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "fma{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.fma.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qdmulh{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqdmulh.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrdmulh{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqrdmulh.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "mull_{1.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "mull{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(16-64)",
|
||||
"args": ["0n", "0n"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qdmull{0.width}_{1.data_type}",
|
||||
"width": [128],
|
||||
"llvm": "sqdmull.{0.llvm_name}",
|
||||
"ret": "s(16-32)",
|
||||
"args": ["0n", "0n"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "hsub{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "hsub{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qsub{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "qsub{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsubhn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "rsubhn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abd{0.width}_{1.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "abd{0.kind}.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "max{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "max{0.kind}.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "min{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "min{0.kind}.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "shl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "shl{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "qshl{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "rshl{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "qrshl{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshrun_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "sqshrun.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshrun_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "sqrshrun.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "qshrn{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "rshrn.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qrshrn_n_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "qrshrn{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w", "U32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sri{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "vsri.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sli{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "vsli.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "vqmovn_{1.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "qxtn{0.kind}.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0w"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abs{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "abs.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "abs{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.fabs.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qabs{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "sqabs.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "qneg{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "sqneg.{0.llvm_name}",
|
||||
"ret": "s(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "clz{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.ctlz.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "cls{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "cls.{0.llvm_name}",
|
||||
"ret": "i(8-32)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "cnt{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.ctpop.{0.llvm_name}",
|
||||
"ret": "i8",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "recpe{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "recpe.{0.llvm_name}",
|
||||
"ret": ["u32","f32"],
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "recps{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "frecps.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "sqrt{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "!llvm.sqrt.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsqrte{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "rsqrte.{0.llvm_name}",
|
||||
"ret": ["u32","f32"],
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "rsqrts{0.width}_{0.data_type}",
|
||||
"width": [64,128],
|
||||
"llvm": "rsqrts.{0.llvm_name}",
|
||||
"ret": "f32",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "bsl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "bsl.{0.llvm_name}",
|
||||
"ret": "i(8-64)",
|
||||
"args": ["0u", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "padd{0.width}_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "padd.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "paddl{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "paddl{0.kind}.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "i(16-64)",
|
||||
"args": ["0dn"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "padal{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "padal{0.kind}.{0.llvm_name}.{1.llvm_name}",
|
||||
"ret": "i(16-64)",
|
||||
"args": ["0", "0dn"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmax{0.width}_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "pmax{0.kind}.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "pmin{0.width}_{0.data_type}",
|
||||
"width": [64, 128],
|
||||
"llvm": "pmin{0.kind}.{0.llvm_name}",
|
||||
"ret": ["i(8-32)","f32"],
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbl1_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbl1",
|
||||
"ret": "i8",
|
||||
"args": ["0", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbx1_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbx1",
|
||||
"ret": "i8",
|
||||
"args": ["0", "0", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbl2_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbl2",
|
||||
"ret": "i8",
|
||||
"args": ["(0,0)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbx2_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbx2",
|
||||
"ret": "i8",
|
||||
"args": ["(0,0)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbl3_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbl3",
|
||||
"ret": "i8",
|
||||
"args": ["(0,0,0)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbx3_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbx3",
|
||||
"ret": "i8",
|
||||
"args": ["0", "(0,0,0)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbl4_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbl4",
|
||||
"ret": "i8",
|
||||
"args": ["(0,0,0,0)f", "0u"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "tbx4_{0.data_type}",
|
||||
"width": [64],
|
||||
"llvm": "tbx4",
|
||||
"ret": "i8",
|
||||
"args": ["0", "(0,0,0,0)f", "0u"]
|
||||
}
|
||||
]
|
||||
}
|
||||
805
src/etc/platform-intrinsics/generator.py
Normal file
805
src/etc/platform-intrinsics/generator.py
Normal file
@ -0,0 +1,805 @@
|
||||
# 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 <LICENSE-APACHE or
|
||||
# http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
# <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
# option. This file may not be copied, modified, or distributed
|
||||
# except according to those terms.
|
||||
|
||||
from __future__ import division, print_function
|
||||
import json
|
||||
import argparse
|
||||
import sys
|
||||
import re
|
||||
import textwrap
|
||||
import itertools
|
||||
|
||||
SPEC = re.compile(
|
||||
r'^(?:(?P<void>V)|(?P<id>[iusfIUSF])(?:\((?P<start>\d+)-(?P<end>\d+)\)|'
|
||||
r'(?P<width>\d+)(:?/(?P<llvm_width>\d+))?)'
|
||||
r'|(?P<reference>\d+))(?P<index>\.\d+)?(?P<modifiers>[vShdnwusfDMC]*)(?P<force_width>x\d+)?'
|
||||
r'(?:(?P<pointer>Pm|Pc)(?P<llvm_pointer>/.*)?|(?P<bitcast>->.*))?$'
|
||||
)
|
||||
|
||||
class PlatformInfo(object):
|
||||
def __init__(self, json):
|
||||
self._platform = json['platform']
|
||||
self._intrinsic_prefix = json['intrinsic_prefix']
|
||||
|
||||
def intrinsic_prefix(self):
|
||||
return self._intrinsic_prefix
|
||||
|
||||
class IntrinsicSet(object):
|
||||
def __init__(self, platform, json):
|
||||
self._llvm_prefix = json['llvm_prefix']
|
||||
self._type_info = json['number_info']
|
||||
self._intrinsics = json['intrinsics']
|
||||
self._widths = json['width_info']
|
||||
self._platform = platform
|
||||
|
||||
def intrinsics(self):
|
||||
for raw in self._intrinsics:
|
||||
yield GenericIntrinsic(self,
|
||||
raw['intrinsic'], raw['width'], raw['llvm'],
|
||||
raw['ret'], raw['args'])
|
||||
|
||||
def platform(self):
|
||||
return self._platform
|
||||
|
||||
def llvm_prefix(self):
|
||||
return self._llvm_prefix
|
||||
|
||||
def width_info(self, bitwidth):
|
||||
return self._widths[str(bitwidth)]
|
||||
|
||||
def number_type_info(self, value):
|
||||
data = self._type_info[value.__class__.__name__.lower()]
|
||||
bitwidth = value.bitwidth()
|
||||
def lookup(raw):
|
||||
if not isinstance(raw, dict):
|
||||
return raw
|
||||
|
||||
try:
|
||||
return raw[str(bitwidth)]
|
||||
except KeyError:
|
||||
return raw['pattern'].format(bitwidth = bitwidth)
|
||||
|
||||
return PlatformTypeInfo(value.llvm_name(),
|
||||
{k: lookup(v) for k, v in data.items()})
|
||||
|
||||
class PlatformTypeInfo(object):
|
||||
def __init__(self, llvm_name, properties, elems = None):
|
||||
if elems is None:
|
||||
self.properties = properties
|
||||
self.llvm_name = llvm_name
|
||||
else:
|
||||
assert properties is None and llvm_name is None
|
||||
self.properties = {}
|
||||
self.elems = elems
|
||||
|
||||
def __repr__(self):
|
||||
return '<PlatformTypeInfo {}, {}>'.format(self.llvm_name, self.properties)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return self.properties[name]
|
||||
|
||||
def __getitem__(self, idx):
|
||||
return self.elems[idx]
|
||||
|
||||
def vectorize(self, length, width_info):
|
||||
props = self.properties.copy()
|
||||
props.update(width_info)
|
||||
return PlatformTypeInfo('v{}{}'.format(length, self.llvm_name), props)
|
||||
|
||||
def pointer(self, llvm_elem):
|
||||
name = self.llvm_name if llvm_elem is None else llvm_elem.llvm_name
|
||||
return PlatformTypeInfo('p0{}'.format(name), self.properties)
|
||||
|
||||
BITWIDTH_POINTER = '<pointer>'
|
||||
|
||||
class Type(object):
|
||||
def __init__(self, bitwidth):
|
||||
self._bitwidth = bitwidth
|
||||
|
||||
def bitwidth(self):
|
||||
return self._bitwidth
|
||||
|
||||
def modify(self, spec, width, previous):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __ne__(self, other):
|
||||
return not (self == other)
|
||||
|
||||
class Void(Type):
|
||||
def __init__(self):
|
||||
Type.__init__(self, 0)
|
||||
|
||||
def compiler_ctor(self):
|
||||
return 'void()'
|
||||
|
||||
def rust_name(self):
|
||||
return '()'
|
||||
|
||||
def type_info(self, platform_info):
|
||||
return None
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Void)
|
||||
|
||||
class Number(Type):
|
||||
def __init__(self, bitwidth):
|
||||
Type.__init__(self, bitwidth)
|
||||
|
||||
def modify(self, spec, width, previous):
|
||||
if spec == 'u':
|
||||
return Unsigned(self.bitwidth())
|
||||
elif spec == 's':
|
||||
return Signed(self.bitwidth())
|
||||
elif spec == 'f':
|
||||
return Float(self.bitwidth())
|
||||
elif spec == 'w':
|
||||
return self.__class__(self.bitwidth() * 2)
|
||||
elif spec == 'n':
|
||||
return self.__class__(self.bitwidth() // 2)
|
||||
elif spec == 'v':
|
||||
return Vector(self, width // self.bitwidth())
|
||||
else:
|
||||
raise ValueError('unknown modification spec {}', spec)
|
||||
|
||||
def type_info(self, platform_info):
|
||||
return platform_info.number_type_info(self)
|
||||
|
||||
def __eq__(self, other):
|
||||
# print(self, other)
|
||||
return self.__class__ == other.__class__ and self.bitwidth() == other.bitwidth()
|
||||
|
||||
class Signed(Number):
|
||||
def __init__(self, bitwidth, llvm_bitwidth = None):
|
||||
Number.__init__(self, bitwidth)
|
||||
self._llvm_bitwidth = llvm_bitwidth
|
||||
|
||||
|
||||
def compiler_ctor(self):
|
||||
if self._llvm_bitwidth is None:
|
||||
return 'i({})'.format(self.bitwidth())
|
||||
else:
|
||||
return 'i_({}, {})'.format(self.bitwidth(),
|
||||
self._llvm_bitwidth)
|
||||
|
||||
def llvm_name(self):
|
||||
bw = self._llvm_bitwidth or self.bitwidth()
|
||||
return 'i{}'.format(bw)
|
||||
|
||||
def rust_name(self):
|
||||
return 'i{}'.format(self.bitwidth())
|
||||
|
||||
class Unsigned(Number):
|
||||
def __init__(self, bitwidth, llvm_bitwidth = None):
|
||||
Number.__init__(self, bitwidth)
|
||||
self._llvm_bitwidth = llvm_bitwidth
|
||||
|
||||
def compiler_ctor(self):
|
||||
if self._llvm_bitwidth is None:
|
||||
return 'u({})'.format(self.bitwidth())
|
||||
else:
|
||||
return 'u_({}, {})'.format(self.bitwidth(),
|
||||
self._llvm_bitwidth)
|
||||
|
||||
def llvm_name(self):
|
||||
bw = self._llvm_bitwidth or self.bitwidth()
|
||||
return 'i{}'.format(bw)
|
||||
|
||||
def rust_name(self):
|
||||
return 'u{}'.format(self.bitwidth())
|
||||
|
||||
class Float(Number):
|
||||
def __init__(self, bitwidth):
|
||||
assert bitwidth in (32, 64)
|
||||
Number.__init__(self, bitwidth)
|
||||
|
||||
def compiler_ctor(self):
|
||||
return 'f({})'.format(self.bitwidth())
|
||||
|
||||
def llvm_name(self):
|
||||
return 'f{}'.format(self.bitwidth())
|
||||
|
||||
def rust_name(self):
|
||||
return 'f{}'.format(self.bitwidth())
|
||||
|
||||
class Vector(Type):
|
||||
def __init__(self, elem, length, bitcast = None):
|
||||
assert isinstance(elem, Type) and not isinstance(elem, Vector)
|
||||
Type.__init__(self,
|
||||
elem.bitwidth() * length)
|
||||
self._length = length
|
||||
self._elem = elem
|
||||
assert bitcast is None or (isinstance(bitcast, Vector) and
|
||||
bitcast._bitcast is None and
|
||||
bitcast._elem.bitwidth() == elem.bitwidth())
|
||||
if bitcast is not None and bitcast._elem != elem:
|
||||
self._bitcast = bitcast._elem
|
||||
else:
|
||||
self._bitcast = None
|
||||
|
||||
def modify(self, spec, width, previous):
|
||||
if spec == 'S':
|
||||
return self._elem
|
||||
elif spec == 'h':
|
||||
return Vector(self._elem, self._length // 2)
|
||||
elif spec == 'd':
|
||||
return Vector(self._elem, self._length * 2)
|
||||
elif spec.startswith('x'):
|
||||
new_bitwidth = int(spec[1:])
|
||||
return Vector(self._elem, new_bitwidth // self._elem.bitwidth())
|
||||
elif spec.startswith('->'):
|
||||
bitcast_to = TypeSpec(spec[2:])
|
||||
choices = list(bitcast_to.enumerate(width, previous))
|
||||
assert len(choices) == 1
|
||||
bitcast_to = choices[0]
|
||||
return Vector(self._elem, self._length, bitcast_to)
|
||||
else:
|
||||
return Vector(self._elem.modify(spec, width, previous), self._length)
|
||||
|
||||
def compiler_ctor(self):
|
||||
if self._bitcast is None:
|
||||
return 'v({}, {})'.format(self._elem.compiler_ctor(),
|
||||
self._length)
|
||||
else:
|
||||
return 'v_({}, {}, {})'.format(self._elem.compiler_ctor(),
|
||||
self._bitcast.compiler_ctor(),
|
||||
self._length)
|
||||
|
||||
def rust_name(self):
|
||||
return '{}x{}'.format(self._elem.rust_name(), self._length)
|
||||
|
||||
def type_info(self, platform_info):
|
||||
elem_info = self._elem.type_info(platform_info)
|
||||
return elem_info.vectorize(self._length,
|
||||
platform_info.width_info(self.bitwidth()))
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Vector) and self._length == other._length and \
|
||||
self._elem == other._elem and self._bitcast == other._bitcast
|
||||
|
||||
class Pointer(Type):
|
||||
def __init__(self, elem, llvm_elem, const):
|
||||
self._elem = elem;
|
||||
self._llvm_elem = llvm_elem
|
||||
self._const = const
|
||||
Type.__init__(self, BITWIDTH_POINTER)
|
||||
|
||||
def modify(self, spec, width, previous):
|
||||
if spec == 'D':
|
||||
return self._elem
|
||||
elif spec == 'M':
|
||||
return Pointer(self._elem, self._llvm_elem, False)
|
||||
elif spec == 'C':
|
||||
return Pointer(self._elem, self._llvm_elem, True)
|
||||
else:
|
||||
return Pointer(self._elem.modify(spec, width, previous), self._llvm_elem, self._const)
|
||||
|
||||
def compiler_ctor(self):
|
||||
if self._llvm_elem is None:
|
||||
llvm_elem = 'None'
|
||||
else:
|
||||
llvm_elem = 'Some({})'.format(self._llvm_elem.compiler_ctor())
|
||||
return 'p({}, {}, {})'.format('true' if self._const else 'false',
|
||||
self._elem.compiler_ctor(),
|
||||
llvm_elem)
|
||||
|
||||
def rust_name(self):
|
||||
return '*{} {}'.format('const' if self._const else 'mut',
|
||||
self._elem.rust_name())
|
||||
|
||||
def type_info(self, platform_info):
|
||||
if self._llvm_elem is None:
|
||||
llvm_elem = None
|
||||
else:
|
||||
llvm_elem = self._llvm_elem.type_info(platform_info)
|
||||
return self._elem.type_info(platform_info).pointer(llvm_elem)
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Pointer) and self._const == other._const \
|
||||
and self._elem == other._elem and self._llvm_elem == other._llvm_elem
|
||||
|
||||
class Aggregate(Type):
|
||||
def __init__(self, flatten, elems):
|
||||
self._flatten = flatten
|
||||
self._elems = elems
|
||||
Type.__init__(self, sum(elem.bitwidth() for elem in elems))
|
||||
|
||||
def __repr__(self):
|
||||
return '<Aggregate {}>'.format(self._elems)
|
||||
|
||||
def modify(self, spec, width, previous):
|
||||
if spec.startswith('.'):
|
||||
num = int(spec[1:])
|
||||
return self._elems[num]
|
||||
else:
|
||||
print(spec)
|
||||
raise NotImplementedError()
|
||||
|
||||
def compiler_ctor(self):
|
||||
return 'agg({}, vec![{}])'.format('true' if self._flatten else 'false',
|
||||
', '.join(elem.compiler_ctor() for elem in self._elems))
|
||||
|
||||
def rust_name(self):
|
||||
return '({})'.format(', '.join(elem.rust_name() for elem in self._elems))
|
||||
|
||||
def type_info(self, platform_info):
|
||||
return PlatformTypeInfo(None, None, [elem.type_info(platform_info) for elem in self._elems])
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, Aggregate) and self._flatten == other._flatten and \
|
||||
self._elems == other._elems
|
||||
|
||||
|
||||
TYPE_ID_LOOKUP = {'i': [Signed, Unsigned],
|
||||
's': [Signed],
|
||||
'u': [Unsigned],
|
||||
'f': [Float]}
|
||||
|
||||
def ptrify(match, elem, width, previous):
|
||||
ptr = match.group('pointer')
|
||||
if ptr is None:
|
||||
return elem
|
||||
else:
|
||||
llvm_ptr = match.group('llvm_pointer')
|
||||
if llvm_ptr is None:
|
||||
llvm_elem = None
|
||||
else:
|
||||
assert llvm_ptr.startswith('/')
|
||||
options = list(TypeSpec(llvm_ptr[1:]).enumerate(width, previous))
|
||||
assert len(options) == 1
|
||||
llvm_elem = options[0]
|
||||
assert ptr in ('Pc', 'Pm')
|
||||
return Pointer(elem, llvm_elem, ptr == 'Pc')
|
||||
|
||||
class TypeSpec(object):
|
||||
def __init__(self, spec):
|
||||
if not isinstance(spec, list):
|
||||
spec = [spec]
|
||||
|
||||
self.spec = spec
|
||||
|
||||
def enumerate(self, width, previous):
|
||||
for spec in self.spec:
|
||||
match = SPEC.match(spec)
|
||||
if match is not None:
|
||||
id = match.group('id')
|
||||
reference = match.group('reference')
|
||||
|
||||
modifiers = []
|
||||
index = match.group('index')
|
||||
if index is not None:
|
||||
modifiers.append(index)
|
||||
modifiers += list(match.group('modifiers') or '')
|
||||
force = match.group('force_width')
|
||||
if force is not None:
|
||||
modifiers.append(force)
|
||||
bitcast = match.group('bitcast')
|
||||
if bitcast is not None:
|
||||
modifiers.append(bitcast)
|
||||
|
||||
if match.group('void') is not None:
|
||||
assert spec == 'V'
|
||||
yield Void()
|
||||
elif id is not None:
|
||||
is_vector = id.islower()
|
||||
type_ctors = TYPE_ID_LOOKUP[id.lower()]
|
||||
|
||||
start = match.group('start')
|
||||
if start is not None:
|
||||
end = match.group('end')
|
||||
llvm_width = None
|
||||
else:
|
||||
start = end = match.group('width')
|
||||
llvm_width = match.group('llvm_width')
|
||||
start = int(start)
|
||||
end = int(end)
|
||||
|
||||
bitwidth = start
|
||||
while bitwidth <= end:
|
||||
for ctor in type_ctors:
|
||||
if llvm_width is not None:
|
||||
assert not is_vector
|
||||
llvm_width = int(llvm_width)
|
||||
assert llvm_width < bitwidth
|
||||
scalar = ctor(bitwidth, llvm_width)
|
||||
else:
|
||||
scalar = ctor(bitwidth)
|
||||
|
||||
if is_vector:
|
||||
elem = Vector(scalar, width // bitwidth)
|
||||
else:
|
||||
assert bitcast is None
|
||||
elem = scalar
|
||||
|
||||
for x in modifiers:
|
||||
elem = elem.modify(x, width, previous)
|
||||
yield ptrify(match, elem, width, previous)
|
||||
bitwidth *= 2
|
||||
elif reference is not None:
|
||||
reference = int(reference)
|
||||
assert reference < len(previous), \
|
||||
'referring to argument {}, but only {} are known'.format(reference,
|
||||
len(previous))
|
||||
ret = previous[reference]
|
||||
for x in modifiers:
|
||||
ret = ret.modify(x, width, previous)
|
||||
yield ptrify(match, ret, width, previous)
|
||||
else:
|
||||
assert False, 'matched `{}`, but didn\'t understand it?'.format(spec)
|
||||
elif spec.startswith('('):
|
||||
if spec.endswith(')'):
|
||||
true_spec = spec[1:-1]
|
||||
flatten = False
|
||||
elif spec.endswith(')f'):
|
||||
true_spec = spec[1:-2]
|
||||
flatten = True
|
||||
else:
|
||||
assert False, 'found unclosed aggregate `{}`'.format(spec)
|
||||
|
||||
for elems in itertools.product(*(TypeSpec(subspec).enumerate(width, previous)
|
||||
for subspec in true_spec.split(','))):
|
||||
yield Aggregate(flatten, elems)
|
||||
elif spec.startswith('['):
|
||||
if spec.endswith(']'):
|
||||
true_spec = spec[1:-1]
|
||||
flatten = False
|
||||
elif spec.endswith(']f'):
|
||||
true_spec = spec[1:-2]
|
||||
flatten = True
|
||||
else:
|
||||
assert False, 'found unclosed aggregate `{}`'.format(spec)
|
||||
elem_spec, count = true_spec.split(';')
|
||||
|
||||
count = int(count)
|
||||
for elem in TypeSpec(elem_spec).enumerate(width, previous):
|
||||
yield Aggregate(flatten, [elem] * count)
|
||||
else:
|
||||
assert False, 'Failed to parse `{}`'.format(spec)
|
||||
|
||||
class GenericIntrinsic(object):
|
||||
def __init__(self, platform, intrinsic, widths, llvm_name, ret, args):
|
||||
self._platform = platform
|
||||
self.intrinsic = intrinsic
|
||||
self.widths = map(int, widths)
|
||||
self.llvm_name = llvm_name
|
||||
self.ret = TypeSpec(ret)
|
||||
self.args = list(map(TypeSpec, args))
|
||||
|
||||
def monomorphise(self):
|
||||
for width in self.widths:
|
||||
# must be a power of two
|
||||
assert width & (width - 1) == 0
|
||||
def recur(processed, untouched):
|
||||
if untouched == []:
|
||||
ret = processed[0]
|
||||
args = processed[1:]
|
||||
yield MonomorphicIntrinsic(self._platform, self.intrinsic, width,
|
||||
self.llvm_name,
|
||||
ret, args)
|
||||
else:
|
||||
raw_arg = untouched[0]
|
||||
rest = untouched[1:]
|
||||
for arg in raw_arg.enumerate(width, processed):
|
||||
for intr in recur(processed + [arg], rest):
|
||||
yield intr
|
||||
|
||||
for x in recur([], [self.ret] + self.args):
|
||||
yield x
|
||||
|
||||
class MonomorphicIntrinsic(object):
|
||||
def __init__(self, platform, intrinsic, width, llvm_name, ret, args):
|
||||
self._platform = platform
|
||||
self._intrinsic = intrinsic
|
||||
self._width = '' if width == 64 else 'q'
|
||||
self._llvm_name = llvm_name
|
||||
self._ret_raw = ret
|
||||
self._ret = ret.type_info(platform)
|
||||
self._args_raw = args
|
||||
self._args = [arg.type_info(platform) for arg in args]
|
||||
|
||||
def llvm_name(self):
|
||||
if self._llvm_name.startswith('!'):
|
||||
return self._llvm_name[1:].format(self._ret, *self._args)
|
||||
else:
|
||||
return self._platform.llvm_prefix() + self._llvm_name.format(self._ret, *self._args)
|
||||
|
||||
def intrinsic_suffix(self):
|
||||
return self._intrinsic.format(self._ret,
|
||||
*self._args,
|
||||
width = self._width)
|
||||
|
||||
def intrinsic_name(self):
|
||||
return self._platform.platform().intrinsic_prefix() + self.intrinsic_suffix()
|
||||
|
||||
def compiler_args(self):
|
||||
return ', '.join(arg.compiler_ctor() for arg in self._args_raw)
|
||||
|
||||
def compiler_ret(self):
|
||||
return self._ret_raw.compiler_ctor()
|
||||
|
||||
def compiler_signature(self):
|
||||
return '({}) -> {}'.format(self.compiler_args(), self.compiler_ret())
|
||||
|
||||
def intrinsic_signature(self):
|
||||
names = 'xyzwabcdef'
|
||||
return '({}) -> {}'.format(', '.join('{}: {}'.format(name, arg.rust_name())
|
||||
for name, arg in zip(names, self._args_raw)),
|
||||
self._ret_raw.rust_name())
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(
|
||||
formatter_class = argparse.RawDescriptionHelpFormatter,
|
||||
description = 'Render an intrinsic definition JSON to various formats.',
|
||||
epilog = textwrap.dedent('''\
|
||||
An intrinsic definition consists of a map with fields:
|
||||
- intrinsic: pattern for the name(s) of the vendor's C intrinsic(s)
|
||||
- llvm: pattern for the name(s) of the internal llvm intrinsic(s)
|
||||
- width: a vector of vector bit-widths the pattern works with
|
||||
- ret: type specifier for the return value
|
||||
- arguments: vector of type specifiers for arguments
|
||||
|
||||
The width and types describe a range of possible intrinsics,
|
||||
and these are fed back into the intrinsic and llvm patterns to
|
||||
create the appropriate definitions.
|
||||
|
||||
## Type specifier grammar
|
||||
|
||||
```
|
||||
type := core_type modifier* suffix?
|
||||
|
||||
core_type := void | vector | scalar | aggregate | reference
|
||||
|
||||
modifier := 'v' | 'h' | 'd' | 'n' | 'w' | 'u' | 's' |
|
||||
'x' number | '.' number
|
||||
suffix := pointer | bitcast
|
||||
pointer := 'Pm' llvm_pointer? | 'Pc' llvm_pointer?
|
||||
llvm_pointer := '/' type
|
||||
bitcast := '->' type
|
||||
|
||||
void := 'V'
|
||||
|
||||
vector := vector_elem width |
|
||||
vector_elem := 'i' | 'u' | 's' | 'f'
|
||||
|
||||
scalar := scalar_type number llvm_width?
|
||||
scalar_type := 'U' | 'S' | 'F'
|
||||
llvm_width := '/' number
|
||||
|
||||
aggregate := '(' (type),* ')' 'f'? | '[' type ';' number ']' 'f'?
|
||||
|
||||
reference := number
|
||||
|
||||
width = number | '(' number '-' number ')'
|
||||
|
||||
number = [0-9]+
|
||||
```
|
||||
|
||||
## Void
|
||||
|
||||
The `V` type corresponds to `void` in LLVM (`()` in
|
||||
Rust). It's likely to only work in return position.
|
||||
|
||||
## Vectors
|
||||
|
||||
The vector grammar is a pattern describing many possibilities
|
||||
for arguments/return value. The `vector_elem` describes the
|
||||
types of elements to use, and the `width` describes the (range
|
||||
of) widths for those elements, which are then placed into a
|
||||
vector with the `width` bitwidth. E.g. if an intrinsic has a
|
||||
`width` that includes 128, and the return value is `i(8-32)`,
|
||||
then some instantiation of that intrinsic will be `u8x16`,
|
||||
`u32x4`, `i32x4`, etc.
|
||||
|
||||
### Elements
|
||||
|
||||
- i: integer, both signed and unsigned
|
||||
- u: unsigned integer
|
||||
- s: signed integer
|
||||
- f: float
|
||||
|
||||
## Scalars
|
||||
|
||||
Similar to vectors, but these describe a single concrete type,
|
||||
not a range. The number is the bitwidth. The optional
|
||||
`llvm_width` is the bitwidth of the integer that should be
|
||||
passed to LLVM (by truncating the Rust argument): this only
|
||||
works with scalar integers and the LLVM width must be smaller
|
||||
than the Rust width.
|
||||
|
||||
### Types
|
||||
|
||||
- U: unsigned integer
|
||||
- S: signed integer
|
||||
- F: float
|
||||
|
||||
## Aggregates
|
||||
|
||||
An aggregate is a collection of multiple types; a tuple in
|
||||
Rust terms, or an unnamed struct in LLVM. The `f` modifiers
|
||||
forces the tuple to be flattened in the LLVM
|
||||
intrinsic. E.g. if `llvm.foo` takes `(F32,S32)`:
|
||||
|
||||
- no `f` corresponds to `declare ... @llvm.foo({float, i32})`.
|
||||
- having an `f` corresponds to `declare ... @llvm.foo(float, i32)`.
|
||||
|
||||
The `[type;number]` form is a just shorter way to write
|
||||
`(...)`, except avoids doing a cartesian product of generic
|
||||
types, e.g. `[S32;2]` is the same as `(S32, S32)`, while
|
||||
`[I32;2]` is describing just the two types `(S32,S32)` and
|
||||
`(U32,U32)` (i.e. doesn't include `(S32,U32)`, `(U32,S32)` as
|
||||
`(I32,I32)` would).
|
||||
|
||||
(Currently aggregates can not contain other aggregates.)
|
||||
|
||||
## References
|
||||
|
||||
A reference uses the type of another argument, with possible
|
||||
modifications. The number refers to the type to use, starting
|
||||
with 0 == return value, 1 == first argument, 2 == second
|
||||
argument, etc.
|
||||
|
||||
## Affixes
|
||||
|
||||
The `modifier` and `suffix` adaptors change the precise
|
||||
representation.
|
||||
|
||||
### Modifiers
|
||||
|
||||
- 'v': put a scalar into a vector of the current width (u32 -> u32x4, when width == 128)
|
||||
- 'S': get the scalar element of a vector (u32x4 -> u32)
|
||||
- 'h': half the length of the vector (u32x4 -> u32x2)
|
||||
- 'd': double the length of the vector (u32x2 -> u32x4)
|
||||
- 'n': narrow the element of the vector (u32x4 -> u16x4)
|
||||
- 'w': widen the element of the vector (u16x4 -> u32x4)
|
||||
- 'u': force a number (vector or scalar) to be unsigned int (f32x4 -> u32x4)
|
||||
- 's': force a number (vector or scalar) to be signed int (u32x4 -> i32x4)
|
||||
- 'f': force a number (vector or scalar) to be float (u32x4 -> f32x4)
|
||||
- 'x' number: force the type to be a vector of bitwidth `number`.
|
||||
- '.' number: get the `number`th element of an aggregate
|
||||
- 'D': dereference a pointer (*mut u32 -> u32)
|
||||
- 'C': make a pointer const (*mut u32 -> *const u32)
|
||||
- 'M': make a pointer mut (*const u32 -> *mut u32)
|
||||
|
||||
### Pointers
|
||||
|
||||
Pointers can be created of any type by appending a `P*`
|
||||
suffix. The `m` vs. `c` chooses mut vs. const. e.g. `S32Pm`
|
||||
corresponds to `*mut i32`, and `i32Pc` corresponds (with width
|
||||
128) to `*const i8x16`, `*const u32x4`, etc.
|
||||
|
||||
The type after the `/` (optional) represents the type used
|
||||
internally to LLVM, e.g. `S32pm/S8` is exposed as `*mut i32`
|
||||
in Rust, but is `i8*` in LLVM. (This defaults to the main
|
||||
type).
|
||||
|
||||
### Bitcast
|
||||
|
||||
The `'->' type` bitcast suffix will cause the value to be
|
||||
bitcast to the right-hand type when calling the intrinsic,
|
||||
e.g. `s32->f32` will expose the intrinsic as `i32x4` at the
|
||||
Rust level, but will cast that vector to `f32x4` when calling
|
||||
the LLVM intrinsic.
|
||||
'''))
|
||||
parser.add_argument('--format', choices=FORMATS, required=True,
|
||||
help = 'Output format.')
|
||||
parser.add_argument('-o', '--out', type=argparse.FileType('w'), default=sys.stdout,
|
||||
help = 'File to output to (default stdout).')
|
||||
parser.add_argument('-i', '--info', type=argparse.FileType('r'),
|
||||
help = 'File containing platform specific information to merge into'
|
||||
'the input files\' header.')
|
||||
parser.add_argument('in_', metavar="FILE", type=argparse.FileType('r'), nargs='+',
|
||||
help = 'JSON files to load')
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
class ExternBlock(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def open(self, platform):
|
||||
return 'extern "platform-intrinsic" {'
|
||||
|
||||
def render(self, mono):
|
||||
return ' fn {}{};'.format(mono.intrinsic_name(),
|
||||
mono.intrinsic_signature())
|
||||
|
||||
def close(self):
|
||||
return '}'
|
||||
|
||||
class CompilerDefs(object):
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def open(self, platform):
|
||||
return '''\
|
||||
// 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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// DO NOT EDIT: autogenerated by etc/platform-intrinsics/generator.py
|
||||
// ignore-tidy-linelength
|
||||
|
||||
#![allow(unused_imports)]
|
||||
|
||||
use {{Intrinsic, i, i_, u, u_, f, v, v_, agg, p, void}};
|
||||
use IntrinsicDef::Named;
|
||||
use rustc::middle::ty;
|
||||
|
||||
// The default inlining settings trigger a pathological behaviour in
|
||||
// LLVM, which causes makes compilation very slow. See #28273.
|
||||
#[inline(never)]
|
||||
pub fn find<'tcx>(_tcx: &ty::ctxt<'tcx>, name: &str) -> Option<Intrinsic> {{
|
||||
if !name.starts_with("{0}") {{ return None }}
|
||||
Some(match &name["{0}".len()..] {{'''.format(platform.intrinsic_prefix())
|
||||
|
||||
def render(self, mono):
|
||||
return '''\
|
||||
"{}" => Intrinsic {{
|
||||
inputs: vec![{}],
|
||||
output: {},
|
||||
definition: Named("{}")
|
||||
}},'''.format(mono.intrinsic_suffix(),
|
||||
mono.compiler_args(),
|
||||
mono.compiler_ret(),
|
||||
mono.llvm_name())
|
||||
|
||||
def close(self):
|
||||
return '''\
|
||||
_ => return None,
|
||||
})
|
||||
}'''
|
||||
|
||||
FORMATS = {
|
||||
'extern-block': ExternBlock(),
|
||||
'compiler-defs': CompilerDefs(),
|
||||
}
|
||||
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
ins = args.in_
|
||||
out = args.out
|
||||
out_format = FORMATS[args.format]
|
||||
info = args.info
|
||||
one_file_no_info = False
|
||||
if len(ins) > 1 and info is None:
|
||||
print('error: cannot have multiple inputs without an info header.', file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
elif info is None:
|
||||
info = ins[0]
|
||||
one_file_no_info = True
|
||||
info_json = json.load(info)
|
||||
platform = PlatformInfo(info_json)
|
||||
|
||||
print(out_format.open(platform), file=out)
|
||||
|
||||
for in_ in ins:
|
||||
|
||||
if one_file_no_info:
|
||||
data = info_json
|
||||
else:
|
||||
data = json.load(in_)
|
||||
data.update(info_json)
|
||||
|
||||
intrinsics = IntrinsicSet(platform, data)
|
||||
for intr in intrinsics.intrinsics():
|
||||
for mono in intr.monomorphise():
|
||||
print(out_format.render(mono), file=out)
|
||||
|
||||
print(out_format.close(), file=out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
194
src/etc/platform-intrinsics/x86/avx.json
Normal file
194
src/etc/platform-intrinsics/x86/avx.json
Normal file
@ -0,0 +1,194 @@
|
||||
{
|
||||
"llvm_prefix": "llvm.x86.avx.",
|
||||
"intrinsics": [
|
||||
{
|
||||
"intrinsic": "256_addsub_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "addsub.{0.data_type}.256",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_dp_ps",
|
||||
"width": [256],
|
||||
"llvm": "dp.ps.256",
|
||||
"ret": "f32",
|
||||
"args": ["0", "0", "S32/8"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_hadd_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "hadd.{0.data_type}.256",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_hsub_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "hsub.{0.data_type}.256",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_max_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "max.{0.data_type}.256",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{0.width_mm}_maskload_{0.data_type}",
|
||||
"width": [128, 256],
|
||||
"llvm": "maskload.{0.data_type_short}{0.width_suffix}",
|
||||
"ret": ["f(32-64)"],
|
||||
"args": ["0SPc/S8", "0s->0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{3.width_mm}_maskstore_{3.data_type}",
|
||||
"width": [128, 256],
|
||||
"llvm": "maskstore.{3.data_type_short}{3.width_suffix}",
|
||||
"ret": "V",
|
||||
"args": ["F(32-64)Pm/S8", "1Dsv->1Dv", "1Dv"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_min_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "min.{0.data_type}.256",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_movemask_ps",
|
||||
"width": [256],
|
||||
"llvm": "movmsk.ps.256",
|
||||
"ret": "S32",
|
||||
"args": ["f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_movemask_pd",
|
||||
"width": [256],
|
||||
"llvm": "movmsk.pd.256",
|
||||
"ret": "S32",
|
||||
"args": ["f64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{0.width_mm}_permutevar_{0.data_type}",
|
||||
"width": [128, 256],
|
||||
"llvm": "vpermilvar.{0.data_type}{0.width_suffix}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0", "0s"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_rcp_ps",
|
||||
"width": [256],
|
||||
"llvm": "rcp.ps.256",
|
||||
"ret": "f32",
|
||||
"args": ["f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_rsqrt_ps",
|
||||
"width": [256],
|
||||
"llvm": "rsqrt.ps.256",
|
||||
"ret": "f32",
|
||||
"args": ["f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_storeu_{2.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "storeu.ps.256",
|
||||
"ret": "V",
|
||||
"args": ["f(32-64)Pm/U8", "1D"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_storeu_si256",
|
||||
"width": [256],
|
||||
"llvm": "storeu.dq.256",
|
||||
"ret": "V",
|
||||
"args": ["u8Pm/U8", "1D"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_sqrt_{0.data_type}",
|
||||
"width": [256],
|
||||
"llvm": "!llvm.sqrt.{0.llvm_name}",
|
||||
"ret": "f(32-64)",
|
||||
"args": ["0"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testc_ps",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestc.ps{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f32", "f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testc_pd",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestc.pd{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f64", "f64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_testc_si256",
|
||||
"width": [256],
|
||||
"llvm": "ptestc.256",
|
||||
"ret": "S32",
|
||||
"args": ["u64", "u64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testnzc_ps",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestnzc.ps{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f32", "f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testnzc_pd",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestnzc.pd{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f64", "f64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_testnzc_si256",
|
||||
"width": [256],
|
||||
"llvm": "ptestnzc.256",
|
||||
"ret": "S32",
|
||||
"args": ["u64", "u64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testz_ps",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestz.ps{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f32", "f32"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "{1.width_mm}_testz_pd",
|
||||
"width": [128, 256],
|
||||
"llvm": "vtestz.pd{1.width_suffix}",
|
||||
"ret": "S32",
|
||||
"args": ["f64", "f64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_testz_si256",
|
||||
"width": [256],
|
||||
"llvm": "ptestz.256",
|
||||
"ret": "S32",
|
||||
"args": ["u64", "u64"]
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_zeroall",
|
||||
"width": [256],
|
||||
"llvm": "vzeroall",
|
||||
"ret": "V",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"intrinsic": "256_zeroupper",
|
||||
"width": [256],
|
||||
"llvm": "vzeroupper",
|
||||
"ret": "V",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user