New upstream version 1.31.0+dfsg1

This commit is contained in:
Ximin Luo 2018-12-14 21:27:17 -08:00
parent 13cf67c4bb
commit 450edc1f0b
112 changed files with 4895 additions and 279 deletions

View File

@ -1 +1 @@
42053f9f07c91cbaad78afe459851a435b346673
abe02cefd6cd1916df62ad7dc80161bea50b72e8

35
src/Cargo.lock generated
View File

@ -180,10 +180,10 @@ version = "0.1.0"
[[package]]
name = "bytecount"
version = "0.3.2"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"simd 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -1035,7 +1035,7 @@ dependencies = [
[[package]]
name = "languageserver-types"
version = "0.45.0"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1413,6 +1413,14 @@ dependencies = [
"stable_deref_trait 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "packed_simd"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cfg-if 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "panic_abort"
version = "0.0.0"
@ -1793,7 +1801,7 @@ dependencies = [
"failure 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"itertools 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)",
"languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1802,7 +1810,7 @@ dependencies = [
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.16.8 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-analysis 0.16.10 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-data 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1822,7 +1830,7 @@ dependencies = [
[[package]]
name = "rls-analysis"
version = "0.16.8"
version = "0.16.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2520,7 +2528,7 @@ version = "1.0.0"
dependencies = [
"assert_cli 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
"derive-new 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2650,11 +2658,6 @@ name = "shlex"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "simd"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "siphasher"
version = "0.2.2"
@ -3207,7 +3210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
"checksum bufstream 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f382711e76b9de6c744cc00d0497baba02fb00a787f088c879f01d09468e32"
"checksum bytecount 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f861d9ce359f56dbcb6e0c2a1cb84e52ad732cadb57b806adeb3c7668caccbd8"
"checksum bytecount 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b92204551573580e078dc80017f36a213eb77a0450e4ddd8cfa0f3f2d1f0178f"
"checksum byteorder 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "74c0b906e9446b0a2e4f760cdb3fa4b2c48cdc6db8766a845c54b6ff063fd2e9"
"checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010"
"checksum cargo_metadata 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d8dfe3adeb30f7938e6c1dd5327f29235d8ada3e898aeb08c343005ec2915a2"
@ -3282,7 +3285,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum json 0.11.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9ad0485404155f45cce53a40d4b2d6ac356418300daed05273d9e26f91c390be"
"checksum jsonrpc-core 8.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ddf83704f4e79979a424d1082dd2c1e52683058056c9280efa19ac5f6bc9033c"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum languageserver-types 0.45.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d91d91d1c23db74187096d191967cb49f49bb175ad6d855fa9229d16ef2c982"
"checksum languageserver-types 0.51.1 (registry+https://github.com/rust-lang/crates.io-index)" = "68de833188ada4e175d04a028f03f244f6370eedbcc75a05604d47d925933f69"
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
"checksum lazy_static 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca488b89a5657b0a2ecd45b95609b3e848cf1755da332a0da46e2b2b1cb371a7"
"checksum lazycell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ddba4c30a78328befecec92fc94970e53b3ae385827d28620f0f5bb2493081e0"
@ -3323,6 +3326,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
"checksum ordslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd20eec3dbe4376829cb7d80ae6ac45e0a766831dca50202ff2d40db46a8a024"
"checksum owning_ref 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cdf84f41639e037b484f93433aa3897863b561ed65c6e59c7073d7c561710f37"
"checksum packed_simd 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25d36de864f7218ec5633572a800109bbe5a1cc8d9d95a967f3daf93ea7e6ddc"
"checksum parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f0802bff09003b291ba756dc7e79313e51cc31667e94afbe847def490424cde5"
"checksum parking_lot_core 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "4db1a8ccf734a7bce794cc19b3df06ed87ab2f3907036b693c68f56b4d4537fa"
"checksum parking_lot_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "06a2b6aae052309c2fd2161ef58f5067bc17bb758377a0de9d4b279d603fdd8a"
@ -3360,7 +3364,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7"
"checksum regex-syntax 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "747ba3b235651f6e2f67dfa8bcdcd073ddb7c243cb21c442fc12395dfcac212d"
"checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5"
"checksum rls-analysis 0.16.8 (registry+https://github.com/rust-lang/crates.io-index)" = "2a1d3a2a8c03e380331aefb8b5e3e06f3065602fbaa6657ba0ac649dc99d8537"
"checksum rls-analysis 0.16.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2de1187cceaf16d7642cc78835a2890b55b35ed9e8a8e3c6348a6297d8dd0fb1"
"checksum rls-blacklist 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "b8ce1fdac03e138c4617ff87b194e1ff57a39bb985a044ccbd8673d30701e411"
"checksum rls-data 0.18.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3a209ce46bb52813cbe0786a7baadc0c1a3f5543ef93f179eda3b841ed72cf2e"
"checksum rls-rustc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9dba7390427aefa953608429701e3665192ca810ba8ae09301e001b7c7bed0"
@ -3396,7 +3400,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum serde_json 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "bb47a3d5c84320222f66d7db21157c4a7407755de41798f9b4c1c40593397b1a"
"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9"
"checksum shlex 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2"
"checksum simd 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0048b17eb9577ac545c61d85c3559b41dfb4cbea41c9bd9ca6a4f73ff05fda84"
"checksum siphasher 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0df90a788073e8d0235a67e50441d47db7c8ad9debd91cbf43736a2a92d36537"
"checksum smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "153ffa32fd170e9944f7e0838edf824a754ec4c1fc64746fcc9fe1f8fa602e5d"
"checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7"

View File

@ -62,6 +62,6 @@ rustfmt-nightly = { path = "tools/rustfmt" }
# here
rustc-workspace-hack = { path = 'tools/rustc-workspace-hack' }
[patch."https://github.com/rust-lang-nursery/rust-clippy"]
[patch."https://github.com/rust-lang/rust-clippy"]
clippy_lints = { path = "tools/clippy/clippy_lints" }
rustc_tools_util = { path = "tools/clippy/rustc_tools_util" }

View File

@ -443,7 +443,8 @@ impl<'a> Builder<'a> {
doc::RustdocBook,
doc::RustByExample,
doc::RustcBook,
doc::CargoBook
doc::CargoBook,
doc::EditionGuide,
),
Kind::Dist => describe!(
dist::Docs,

View File

@ -70,6 +70,7 @@ macro_rules! book {
book!(
Nomicon, "src/doc/nomicon", "nomicon";
Reference, "src/doc/reference", "reference";
EditionGuide, "src/doc/edition-guide", "edition-guide";
RustdocBook, "src/doc/rustdoc", "rustdoc";
RustcBook, "src/doc/rustc", "rustc";
RustByExample, "src/doc/rust-by-example", "rust-by-example";

View File

@ -51,7 +51,7 @@ fi
#
# FIXME: need a scheme for changing this `nightly` value to `beta` and `stable`
# either automatically or manually.
export RUST_RELEASE_CHANNEL=beta
export RUST_RELEASE_CHANNEL=stable
if [ "$DEPLOY$DEPLOY_ALT" != "" ]; then
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNEL"
RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"

View File

@ -0,0 +1,13 @@
language: rust
cache: cargo
rust: nightly
before_script:
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
- (test -x $HOME/.cargo/bin/mdbook || cargo install mdbook)
- cargo install-update -a
- mdbook --version
script:
- mdbook build
- mdbook test
after_success:
- test $TRAVIS_PULL_REQUEST == "false" && test $TRAVIS_BRANCH == "master" && bash deploy.sh

View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,25 @@
Copyright (c) 2018 The Rust Project Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@ -0,0 +1,63 @@
# The Rust Edition Guide
[![Build Status](https://travis-ci.org/rust-lang-nursery/edition-guide.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/edition-guide)
This book explains the concept of "editions", major new eras in [Rust]'s
development. You can [read the book
online](https://rust-lang-nursery.github.io/edition-guide/).
[Rust]: https://www.rust-lang.org/
## License
The Edition Guide is dual licensed under `MIT`/`Apache2`, just like Rust itself.
See the `LICENSE-*` files in this repository for more details.
## Building locally
You can also build the book and read it locally if you'd like.
### Requirements
Building the book requires [mdBook]. To get it:
[mdBook]: https://github.com/azerupi/mdBook
```bash
$ cargo install mdbook
```
### Building
To build the book, do this:
```bash
$ mdbook build
```
The output will be in the `book` subdirectory. To check it out, open it in
your web browser.
_Firefox:_
```shell
$ firefox book/index.html # Linux
$ open -a "Firefox" book/index.html # OS X
$ Start-Process "firefox.exe" .\book\index.html # Windows (PowerShell)
$ start firefox.exe .\book\index.html # Windows (Cmd)
```
_Chrome:_
```shell
$ google-chrome book/index.html # Linux
$ open -a "Google Chrome" book/index.html # OS X
$ Start-Process "chrome.exe" .\book\index.html # Windows (PowerShell)
$ start chrome.exe .\book\index.html # Windows (Cmd)
```
To run the tests:
```bash
$ mdbook test
```

View File

@ -0,0 +1,5 @@
[book]
authors = ["The Rust Project Developers"]
multilingual = false
src = "src"
title = "The Edition Guide"

View File

@ -0,0 +1,27 @@
#!/bin/bash
set -o errexit -o nounset
if [ "$TRAVIS_BRANCH" != "master" ]
then
echo "This commit was made against the $TRAVIS_BRANCH and not the master! No deploy!"
exit 0
fi
rev=$(git rev-parse --short HEAD)
cd book
git init
git config user.name "Steve Klabnik"
git config user.email "steve@steveklabnik.com"
git remote add upstream "https://$GH_TOKEN@github.com/rust-lang-nursery/edition-guide.git"
git fetch upstream
git reset upstream/gh-pages
touch .
git add -A .
git commit -m "rebuild pages at ${rev}"
git push -q upstream HEAD:gh-pages

View File

@ -0,0 +1,86 @@
# The Edition Guide
[Introduction](introduction.md)
## What are editions?
- [What are editions?](editions/index.md)
- [Creating a new project](editions/creating-a-new-project.md)
- [Transitioning an existing project to a new edition](editions/transitioning-an-existing-project-to-a-new-edition.md)
## Rust 2015
- [Rust 2015](rust-2015/index.md)
## Rust 2018
- [Rust 2018](rust-2018/index.md)
- [Module system](rust-2018/module-system/index.md)
- [Raw identifiers](rust-2018/module-system/raw-identifiers.md)
- [Path clarity](rust-2018/module-system/path-clarity.md)
- [More visibility modifiers](rust-2018/module-system/more-visibility-modifiers.md)
- [Nested imports with `use`](rust-2018/module-system/nested-imports-with-use.md)
- [Error handling and panics](rust-2018/error-handling-and-panics/index.md)
- [The `?` operator for easier error handling](rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md)
- [`?` in `main` and tests](rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md)
- [Controlling panics with `std::panic`](rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md)
- [Aborting on panic](rust-2018/error-handling-and-panics/aborting-on-panic.md)
- [Control flow](rust-2018/control-flow/index.md)
- [Loops can `break` with a value](rust-2018/control-flow/loops-can-break-with-a-value.md)
- [`async`/`await` for easier concurrency](rust-2018/control-flow/async-await-for-easier-concurrency.md)
- [Trait system](rust-2018/trait-system/index.md)
- [`impl Trait` for returning complex types with ease](rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.md)
- [`dyn Trait` for trait objects](rust-2018/trait-system/dyn-trait-for-trait-objects.md)
- [More container types support trait objects](rust-2018/trait-system/more-container-types-support-trait-objects.md)
- [Associated constants](rust-2018/trait-system/associated-constants.md)
- [No more anonymous parameters](rust-2018/trait-system/no-anon-params.md)
- [Slice patterns](rust-2018/slice-patterns.md)
- [Ownership and lifetimes](rust-2018/ownership-and-lifetimes/index.md)
- [Non-lexical lifetimes](rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.md)
- [Default `match` bindings](rust-2018/ownership-and-lifetimes/default-match-bindings.md)
- [`'_`, the anonymous lifetime](rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.md)
- [Lifetime elision in `impl`](rust-2018/ownership-and-lifetimes/lifetime-elision-in-impl.md)
- [`T: 'a` inference in structs](rust-2018/ownership-and-lifetimes/inference-in-structs.md)
- [Simpler lifetimes in `static` and `const`](rust-2018/ownership-and-lifetimes/simpler-lifetimes-in-static-and-const.md)
- [Data types](rust-2018/data-types/index.md)
- [Field init shorthand](rust-2018/data-types/field-init-shorthand.md)
- [`..=` for inclusive ranges](rust-2018/data-types/inclusive-ranges.md)
- [128 bit integers](rust-2018/data-types/128-bit-integers.md)
- ["Operator-equals" are now implementable](rust-2018/data-types/operator-equals-are-now-implementable.md)
- [`union` for an unsafe form of `enum`](rust-2018/data-types/union-for-an-unsafe-form-of-enum.md)
- [Choosing alignment with the `repr` attribute](rust-2018/data-types/choosing-alignment-with-the-repr-attribute.md)
- [SIMD for faster computing](rust-2018/simd-for-faster-computing.md)
- [Macros](rust-2018/macros/index.md)
- [Custom Derive](rust-2018/macros/custom-derive.md)
- [Macro changes](rust-2018/macros/macro-changes.md)
- [At most one repetition](rust-2018/macros/at-most-once.md)
- [The compiler](rust-2018/the-compiler/index.md)
- [Improved error messages](rust-2018/the-compiler/improved-error-messages.md)
- [Incremental Compilation for faster compiles](rust-2018/the-compiler/incremental-compilation-for-faster-compiles.md)
- [An attribute for deprecation](rust-2018/the-compiler/an-attribute-for-deprecation.md)
- [Rustup for managing Rust versions](rust-2018/rustup-for-managing-rust-versions.md)
- [Cargo and crates.io](rust-2018/cargo-and-crates-io/index.md)
- [`cargo check` for faster checking](rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.md)
- [`cargo install` for easy installation of tools](rust-2018/cargo-and-crates-io/cargo-install-for-easy-installation-of-tools.md)
- [`cargo new` defaults to a binary project](rust-2018/cargo-and-crates-io/cargo-new-defaults-to-a-binary-project.md)
- [`cargo rustc` for passing arbitrary flags to `rustc`](rust-2018/cargo-and-crates-io/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md)
- [Cargo workspaces for multi-package projects](rust-2018/cargo-and-crates-io/cargo-workspaces-for-multi-package-projects.md)
- [Multi-file `examples`](rust-2018/cargo-and-crates-io/multi-file-examples.md)
- [Replacing dependencies with `patch`](rust-2018/cargo-and-crates-io/replacing-dependencies-with-patch.md)
- [Cargo can use a local registry replacement](rust-2018/cargo-and-crates-io/cargo-can-use-a-local-registry-replacement.md)
- [Crates.io disallows wildcard dependencies](rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.md)
- [Documentation](rust-2018/documentation/index.md)
- [New editions of the "the book"](rust-2018/documentation/new-editions-of-the-book.md)
- [The Rust Bookshelf](rust-2018/documentation/the-rust-bookshelf.md)
- [The Rustonomicon](rust-2018/documentation/the-rustonomicon.md)
- [Full documentation for `std::os`](rust-2018/documentation/std-os-has-documentation-for-all-platforms.md)
- [`rustdoc`](rust-2018/rustdoc/index.md)
- [Documentation tests can now `compile-fail`](rust-2018/rustdoc/documentation-tests-can-now-compile-fail.md)
- [Rustdoc uses CommonMark](rust-2018/rustdoc/rustdoc-uses-commonmark.md)
- [Platform and target support](rust-2018/platform-and-target-support/index.md)
- [`libcore` for low-level Rust](rust-2018/platform-and-target-support/libcore-for-low-level-rust.md)
- [WebAssembly support](rust-2018/platform-and-target-support/webassembly-support.md)
- [Global allocators](rust-2018/platform-and-target-support/global-allocators.md)
- [MSVC toolchain support](rust-2018/platform-and-target-support/msvc-toolchain-support.md)
- [MUSL support for fully static binaries](rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md)
- [`cdylib` crates for C interoperability](rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md)

View File

@ -0,0 +1,35 @@
# Creating a new project
When you create a new project with Cargo, it will automatically add
configuration for the latest edition:
```console
> cargo +nightly new foo
Created binary (application) `foo` project
> cat .\foo\Cargo.toml
[package]
name = "foo"
version = "0.1.0"
authors = ["your name <you@example.com>"]
edition = "2018"
[dependencies]
```
That `edition = "2018"` setting will configure your package to use Rust 2018.
No more configuration needed!
If you'd prefer to use an older edition, you can change the value in that
key, for example:
```toml
[package]
name = "foo"
version = "0.1.0"
authors = ["your name <you@example.com>"]
edition = "2015"
[dependencies]
```
This will build your package in Rust 2015.

View File

@ -0,0 +1,68 @@
# What are Editions?
Rust ships releases on a six-week cycle. This means that users get a constant
stream of new features. This is much faster than updates for other languages,
but this also means that each update is smaller. After a while, all of those
tiny changes add up. But, from release to release, it can be hard to look back
and say *"Wow, between Rust 1.10 and Rust 1.20, Rust has changed a lot!"*
Every two or three years, we'll be producing a new *edition* of Rust. Each
edition brings together the features that have landed into a clear package, with
fully updated documentation and tooling. New editions ship through the usual
release process.
This serves different purposes for different people:
- For active Rust users, it brings together incremental changes into an
easy-to-understand package.
- For non-users, it signals that some major advancements have landed, which
might make Rust worth another look.
- For those developing Rust itself, it provides a rallying point for the project as a
whole.
## Compatibility
When a new edition becomes available in the compiler, crates must explicitly opt
in to it to take full advantage. This opt in enables editions to contain
incompatible changes, like adding a new keyword that might conflict with
identifiers in code, or turning warnings into errors. A Rust compiler will
support all editions that existed prior to the compiler's release, and can link
crates of any supported editions together.
Edition changes only affect the way the compiler initially parses the code.
Therefore, if you're using Rust 2015, and
one of your dependencies uses Rust 2018, it all works just fine. The opposite
situation works as well.
Just to be clear: most features will be available on all editions.
People using any edition of Rust will continue to see improvements as new
stable releases are made. In some cases however, mainly when new keywords are
added, but sometimes for other reasons, there may be new features that are only
available in later editions. You only need to upgrade if you want to take
advantage of such features.
## Trying out the 2018 edition
At the time of writing, there are two editions: 2015 and 2018. 2015 is today's
Rust; Rust 2018 is currently in beta, and will land in stable in Rust 1.31, on December 6, 2018.
To give the 2018 edition a try, install the beta toolchain:
```console
> rustup install beta
````
If you want the really bleeding edge, you can try nightly:
```console
> rustup install nightly
```
When you see commands like `cargo fix` elsewhere in this guide, you may
need to preface them with the toolchain:
```console
> cargo +beta fix --edition
> cargo +nightly fix --edition
```

View File

@ -0,0 +1,144 @@
# Transitioning an existing project to a new edition
New editions might change the way you write Rust they add new syntax,
language, and library features, and also remove features. For example, `try`,
`async`, and `await` are keywords in Rust 2018, but not Rust 2015. If you
have a project that's using Rust 2015, and you'd like to use Rust 2018 for it
instead, there's a few steps that you need to take.
> It's our intention that the migration to new editions is as smooth an
> experience as possible. If it's difficult for you to upgrade to Rust 2018,
> we consider that a bug. If you run into problems with this process, please
> [file a bug](https://github.com/rust-lang/rust/issues/new). Thank you!
Here's an example. Imagine we have a crate that has this code in
`src/lib.rs`:
```rust
trait Foo {
fn foo(&self, Box<Foo>);
}
```
This code uses an anonymous parameter, that `Box<Foo>`. This is [not
supported in Rust 2018](rust-2018/trait-system/no-anon-params.html), and
so this would fail to compile. Let's get this code up to date!
## Updating your code to be compatible with the new edition
Your code may or may not use features that are incompatible with the new
edition. In order to help transition to Rust 2018, we've included a new
subcommand with Cargo. To start, let's run it:
```console
> cargo fix --edition
```
This will check your code, and automatically fix any issues that it can.
Let's look at `src/lib.rs` again:
```rust
trait Foo {
fn foo(&self, _: Box<Foo>);
}
```
It's re-written our code to introduce a parameter name for that trait object.
In this case, since it had no name, `cargo fix` will replace it with `_`,
which is conventional for unusued variables.
`cargo fix` is still pretty new, and so it can't always fix your code automatically.
If `cargo fix` can't fix something, it will print the warning that it cannot fix
to the console. If you see one of these warnings, you'll have to update your code
manually. See the corresponding section of this guide for help, and if you have
problems, please seek help at the [user's forums](https://users.rust-lang.org/).
Keep running `cargo fix --edition` until you have no more warnings.
Congrats! Your code is now valid in both Rust 2015 and Rust 2018!
## Enabling the new edition to use new features
In order to use some new features, you must explicitly opt in to the new
edition. Once you're ready to commit, change your `Cargo.toml` to add the new
`edition` key/value pair. For example:
```toml
[package]
name = "foo"
version = "0.1.0"
authors = ["Your Name <you@example.com>"]
edition = "2018"
```
If there's no `edition` key, Cargo will default to Rust 2015. But in this case,
we've chosen `2018`, and so our code is compiling with Rust 2018!
## Writing idiomatic code in a new edition
Editions are not only about new features and removing old ones. In any programming
language, idioms change over time, and Rust is no exception. While old code
will continue to compile, it might be written with different idioms today.
Our sample code contains an outdated idiom. Here it is again:
```rust
trait Foo {
fn foo(&self, _: Box<Foo>);
}
```
In Rust 2018, it's considered idiomatic to use the [`dyn`
keyword](rust-2018/trait-system/dyn-trait-for-trait-objects.html) for
trait objects.
Eventually, we want `cargo fix` to fix all these idioms automatically in the same
manner we did for upgrading to the 2018 edition. **Currently,
though, the *"idiom lints"* are not ready for widespread automatic fixing.** The
compiler isn't making `cargo fix`-compatible suggestions in many cases right
now, and it is making incorrect suggestions in others. Enabling the idiom lints,
even with `cargo fix`, is likely to leave your crate either broken or with many
warnings still remaining.
We have plans to make these idiom migrations a seamless part of the Rust 2018
experience, but we're not there yet. As a result the following instructions are
recommended only for the intrepid who are willing to work through a few
compiler/Cargo bugs!
With that out of the way, we can instruct Cargo to fix our code snippet with:
```console
$ cargo fix --edition-idioms
```
Afterwards, `src/lib.rs` looks like this:
```rust
trait Foo {
fn foo(&self, _: Box<dyn Foo>);
}
```
We're now more idiomatic, and we didn't have to fix our code manually!
Note that `cargo fix` may still not be able to automatically update our code.
If `cargo fix` can't fix something, it will print a warning to the console, and
you'll have to fix it manually.
As mentioned before, there are known bugs around the idiom lints which
means they're not all ready for prime time yet. You may get a scary-looking
warning to report a bug to Cargo, which happens whenever a fix proposed by
`rustc` actually caused code to stop compiling by accident. If you'd like `cargo
fix` to make as much progress as possible, even if it causes code to stop
compiling, you can execute:
```console
$ cargo fix --edition-idioms --broken-code
```
This will instruct `cargo fix` to apply automatic suggestions regardless of
whether they work or not. Like usual, you'll see the compilation result after
all fixes are applied. If you notice anything wrong or unusual, please feel free
to report an issue to Cargo and we'll help prioritize and fix it.
Enjoy the new edition!

View File

@ -0,0 +1,16 @@
# Introduction
Welcome to the Rust Edition Guide! "Editions" are Rust's way of communicating
large changes in the way that it feels to write Rust code.
In this guide, we'll discuss:
* What editions are
* What each edition is about
* How to migrate your code from one edition to another
Note that the standard library grows with each Rust release; there are *many*
additions to the standard library that are not called out in this guide. Only
the major ones are, but there's tons of medium and small things that are
great too. You may want to check out [the standard library
documentation](https://doc.rust-lang.org/std/) as well.

View File

@ -0,0 +1,18 @@
# Rust 2015
Rust 2015 has a theme of "stability". It commenced with the release of 1.0,
and is the "default edition". The edition system was conceived in late 2017,
but Rust 1.0 was released in May of 2015. As such, 2015 is the edition
that you get when you don't specify any particular edition, for backwards
compatibility reasons.
"Stability" is the theme of Rust 2015 because 1.0 marked a huge change in
Rust development. Previous to Rust 1.0, Rust was changing on a daily basis.
This made it very difficult to write large software in Rust, and made it
difficult to learn. With the release of Rust 1.0 and Rust 2015, we committed
to backwards compatibility, ensuring a solid foundation for people to build
projects on top of.
Since it's the default edition, there's no way to port your code to Rust
2015; it just *is*. You'll be transitioning *away* from 2015, but never
really *to* 2015. As such, there's not much else to say about it!

View File

@ -0,0 +1,38 @@
# Cargo can use a local registry replacement
![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg)
Cargo finds its packages in a "source". The default source is [crates.io](https://crates.io). However, you
can choose a different source in your `.cargo/config`:
```toml
[source.crates-io]
replace-with = 'my-awesome-registry'
[source.my-awesome-registry]
registry = 'https://github.com/my-awesome/registry-index'
```
This configuration means that instead of using crates.io, Cargo will query
the `my-awesome-registry` source instead (configured to a different index
here). This alternate source *must be the exact same* as the crates.io index.
Cargo assumes that replacement sources are exact 1:1 mirrors in this respect,
and the following support is designed around that assumption.
When generating a lock file for crate using a replacement registry, the
original registry will be encoded into the lock file. For example in the
configuration above, all lock files will still mention crates.io as the
registry that packages originated from. This semantically represents how
crates.io is the source of truth for all crates, and this is upheld because
all replacements have a 1:1 correspondance.
Overall, this means that no matter what replacement source you're working
with, you can ship your lock file to anyone else and you'll all still have
verifiably reproducible builds!
This has enabled tools like
[`cargo-vendor`](https://github.com/alexcrichton/cargo-vendor) and
[`cargo-local-registry`](https://github.com/alexcrichton/cargo-local-registry),
which are often useful for "offline builds." They prepare the list of all
Rust dependencies ahead of time, which lets you ship them to a build machine
with ease.

View File

@ -0,0 +1,54 @@
# `cargo check` for faster checking
![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg)
`cargo check` is a new subcommand should speed up the development
workflow in many cases.
What does it do? Let's take a step back and talk about how `rustc` compiles
your code. Compilation has many "passes", that is, there are many distinct
steps that the compiler takes on the road from your source code to producing
the final binary. However, you can think of this process in two big steps:
first, `rustc` does all of its safety checks, makes sure your syntax is
correct, all that stuff. Second, once it's satisfied that everything is in
order, it produces the actual binary code that you end up executing.
It turns out that that second step takes a lot of time. And most of the time,
it's not neccesary. That is, when you're working on some Rust code, many
developers will get into a workflow like this:
1. Write some code.
2. Run `cargo build` to make sure it compiles.
3. Repeat 1-2 as needed.
4. Run `cargo test` to make sure your tests pass.
5. Try the binary yourself
6. GOTO 1.
In step two, you never actually run your code. You're looking for feedback
from the compiler, not to actually run the binary. `cargo check` supports
exactly this use-case: it runs all of the compiler's checks, but doesn't
produce the final binary. To use it:
```console
$ cargo check
```
where you may normally `cargo build`. The workflow now looks like:
1. Write some code.
2. Run `cargo check` to make sure it compiles.
3. Repeat 1-2 as needed.
4. Run `cargo test` to make sure your tests pass.
5. Run `cargo build` to build a binary and try it yourself
6. GOTO 1.
So how much speedup do you actually get? Like most performance related
questions, the answer is "it depends." Here are some very un-scientific
benchmarks at the time of writing.
| build | performance | check performance | speedup |
|--------|-------------|-------------------|---------|
| initial compile | 11s | 5.6s | 1.96x |
| second compile (no changes) | 3s | 1.9s | 1.57x |
| third compile with small change | 5.8s | 3s | 1.93x |

View File

@ -0,0 +1,34 @@
# `cargo install` for easy installation of tools
![Minimum Rust version: 1.5](https://img.shields.io/badge/Minimum%20Rust%20Version-1.5-brightgreen.svg)
Cargo has grown a new `install` command. This is intended to be used for installing
new subcommands for Cargo, or tools for Rust developers. This doesn't replace the need
to build real, native packages for end-users on the platforms you support.
For example, this guide is created with [`mdbook`](https://crates.io/crates/mdbook). You
can install it on your system with
```console
$ cargo install mdbook
```
And then use it with
```console
$ mdbook --help
```
As an example of extending Cargo, you can use the [`cargo-update`](https://crates.io/crates/cargo-update)
package. To install it:
```console
$ cargo install cargo-update
```
This will allow you to use this command, which checks everything you've `cargo install`'d and
updates it to the latest version:
```console
$ cargo install-update -a
```

View File

@ -0,0 +1,18 @@
# `cargo new` defaults to a binary project
![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg)
`cargo new` will now default to generating a binary, rather than a library.
We try to keep Cargos CLI quite stable, but this change is important, and is
unlikely to cause breakage.
For some background, cargo new accepts two flags: `--lib`, for creating
libraries, and `--bin`, for creating binaries, or executables. If you dont
pass one of these flags, it used to default to `--lib`. At the time, we made
this decision because each binary (often) depends on many libraries, and so
we thought the library case would be more common. However, this is incorrect;
each library is depended upon by many binaries. Furthermore, when getting
started, what you often want is a program you can run and play around with.
Its not just new Rustaceans though; even very long-time community members
have said that they find this default surprising. As such, weve changed it,
and it now defaults to `--bin`.

View File

@ -0,0 +1,21 @@
# `cargo rustc` for passing arbitrary flags to rustc
![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg)
`cargo rustc` is a new subcommand for Cargo that allows you to pass arbitrary
`rustc` flags through Cargo.
For example, Cargo does not have a way to pass unstable flags built-in. But
if we'd like to use `print-type-sizes` to see what layout information our
types have. We can run this:
```console
$ cargo rustc -- -Z print-type-sizes
```
And we'll get a bunch of output describing the size of our types.
## Note
`cargo rustc` only passes these flags to invocations of your crate, and not to any `rustc`
invocations used to build dependencies. If you'd like to do that, see `$RUSTFLAGS`.

View File

@ -0,0 +1,30 @@
# Cargo workspaces for multi-package projects
![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg)
Cargo used to have two levels of organization:
* A *package* contains one or more crates
* A crate has one or more modules
Cargo now has an additional level:
* A *workspace* contains one or more packages
This can be useful for larger projects. For example, [the `futures` package]
is a *workspace* that contains many related packages:
* futures
* futures-util
* futures-io
* futures-channel
and more.
[the `futures` package]: https://github.com/rust-lang-nursery/futures-rs
Workspaces allow these packages to be developed individually, but they share
a single set of dependencies, and therefore have a single target directory
and a single `Cargo.lock`.
For more details about workspaces, please see [the Cargo documentation](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-workspace-section).

View File

@ -0,0 +1,25 @@
# Crates.io disallows wildcard dependencies
![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg)
Crates.io will not allow you to upload a package with a wildcard dependency.
In other words, these:
```toml
[dependencies]
regex = "*"
```
A wildcard dependency means that you work with any possible version of your
dependency. This is highly unlikely to be true, and would cause unnecessary
breakage in the ecosystem.
Instead, depend on a version range. For example, `^` is the default, so
you could use
```toml
[dependencies]
regex = "1.0.0"
```
instead. `>`, `<=`, and all of the other, non-`*` ranges work as well.

View File

@ -0,0 +1,6 @@
# Cargo and crates.io
[check]: rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.html
In this chapter of the guide, we discuss a few improvements to `cargo` and crates.io.
A notable addition here is the new [`cargo check`][check] command.

View File

@ -0,0 +1,22 @@
# Multi-file examples
![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg)
Cargo has an `examples` feature for showing people how to use your package.
By putting individual files inside of the top-level `examples` directory, you
can create multiple examples.
But what if your example is too big for a single file? Cargo supports adding
sub-directories inside of `examples`, and looks for a `main.rs` inside of
them to build the example. It looks like this:
```text
my-package
└──src
└── lib.rs // code here
└──examples
└── simple-example.rs // a single-file example
└── complex-example
└── helper.rs
└── main.rs // a more complex example that also uses `helper` as a submodule
```

View File

@ -0,0 +1,35 @@
# Replacing dependencies with patch
![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg)
The `[patch]` section of your `Cargo.toml` can be used when you want to
override certain parts of your dependency graph.
> Cargo has a `[replace]` feature that is similar; while we don't intend to deprecate
> or remove `[replace]`, you should prefer `[patch]` in all circumstances.
So whats it look like? Lets say we have a Cargo.toml that looks like this:
```toml
[dependencies]
foo = "1.2.3"
```
In addition, our `foo` package depends on a `bar` crate, and we find a bug in `bar`.
To test this out, wed download the source code for `bar`, and then update our
`Cargo.toml`:
```toml
[dependencies]
foo = "1.2.3"
[patch.crates-io]
bar = { path = '/path/to/bar' }
```
Now, when you `cargo build`, it will use the local version of `bar`, rather
than the one from crates.io that `foo` depends on. You can then try out your
changes, and fix that bug!
For more details, see [the documentation for
`patch`](https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section).

View File

@ -0,0 +1,7 @@
# async/await for easier concurrency
![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg)
The initial release of Rust 2018 won't ship with `async`/`await` support, but
we have reserved the keywords so that a future release will contain them.
We'll update this page when it's closer to shipping!

View File

@ -0,0 +1,6 @@
# Control flow
[async_await]: rust-2018/control-flow/async-await-for-easier-concurrency.html
In this chapter of the guide, we discuss a few improvements to control flow.
The most notable of these *will* be [`async` and `await`][async_await].

View File

@ -0,0 +1,26 @@
# `loop`s can break with a value
![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg)
`loop`s can now break with a value:
```rust
// old code
let x;
loop {
x = 7;
break;
}
// new code
let x = loop { break 7; };
```
Rust has traditionally positioned itself as an “expression oriented
language”, that is, most things are expressions that evaluate to a value,
rather than statements. `loop` stuck out as strange in this way, as it was
previously a statement.
For now, this only applies to `loop`, and not things like `while` or `for`.
It's not clear yet, but we may add this to those in the future.

View File

@ -0,0 +1,17 @@
# 128 bit integers
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
A very simple feature: Rust now has 128 bit integers!
```rust
let x: i128 = 0;
let y: u128 = 0;
```
These are twice the size of `u64`, and so can hold more values. More specifically,
* `u128`: `0` - `340,282,366,920,938,463,463,374,607,431,768,211,455`
* `i128`: `170,141,183,460,469,231,731,687,303,715,884,105,728` - `170,141,183,460,469,231,731,687,303,715,884,105,727`
Whew!

View File

@ -0,0 +1,55 @@
# Choosing alignment with the repr attribute
![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg)
From [Wikipedia](https://en.wikipedia.org/wiki/Data_structure_alignment):
> The CPU in modern computer hardware performs reads and writes to memory
> most efficiently when the data is naturally aligned, which generally means
> that the data address is a multiple of the data size. Data alignment refers
> to aligning elements according to their natural alignment. To ensure natural
> alignment, it may be necessary to insert some padding between structure
> elements or after the last element of a structure.
The `#[repr]` attribute has a new parameter, `align`, that sets the alignment of your struct:
```rust
struct Number(i32);
assert_eq!(std::mem::align_of::<Number>(), 4);
assert_eq!(std::mem::size_of::<Number>(), 4);
#[repr(align(16))]
struct Align16(i32);
assert_eq!(std::mem::align_of::<Align16>(), 16);
assert_eq!(std::mem::size_of::<Align16>(), 16);
```
If youre working with low-level stuff, control of these kinds of things can
be very important!
The alignment of a type is normally not worried about as the compiler will
"do the right thing" of picking an appropriate alignment for general use
cases. There are situations, however, where a nonstandard alignment may be
desired when operating with foreign systems. For example these sorts of
situations tend to necessitate or be much easier with a custom alignment:
* Hardware can often have obscure requirements such as "this structure is
aligned to 32 bytes" when it in fact is only composed of 4-byte values. While
this can typically be manually calculated and managed, it's often also useful
to express this as a property of a type to get the compiler to do a little
extra work instead.
* C compilers like `gcc` and `clang` offer the ability to specify a custom
alignment for structures, and Rust can much more easily interoperate with
these types if Rust can also mirror the request for a custom alignment (e.g.
passing a structure to C correctly is much easier).
* Custom alignment can often be used for various tricks here and there and is
often convenient as "let's play around with an implementation" tool. For
example this can be used to statically allocate page tables in a kernel or
create an at-least cache-line-sized structure easily for concurrent
programming.
The purpose of this feature is to provide a lightweight annotation to alter
the compiler-inferred alignment of a structure to enable these situations
much more easily.

View File

@ -0,0 +1,49 @@
# Field init shorthand
![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg)
In older Rust, when initializing a struct, you must always give the full set of `key: value` pairs
for its fields:
```rust
struct Point {
x: i32,
y: i32,
}
let a = 5;
let b = 6;
let p = Point {
x: a,
y: b,
};
```
However, often these variables would have the same names as the fields. So you'd end up
with code that looks like this:
```rust,ignore
let p = Point {
x: x,
y: y,
};
```
Now, if the variable is of the same name, you don't have to write out both, just write out the key:
```rust
struct Point {
x: i32,
y: i32,
}
let x = 5;
let y = 6;
// new
let p = Point {
x,
y,
};
```

View File

@ -0,0 +1,72 @@
# `..=` for inclusive ranges
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
Since well before Rust 1.0, youve been able to create exclusive ranges with
.. like this:
```
for i in 1..3 {
println!("i: {}", i);
}
```
This will print `i: 1` and then `i: 2`. Today, you can now create an
inclusive range, like this:
```rust
for i in 1..=3 {
println!("i: {}", i);
}
```
This will print `i: 1` and then `i: 2` like before, but also `i: 3`; the
three is included in the range. Inclusive ranges are especially useful if you
want to iterate over every possible value in a range. For example, this is a
surprising Rust program:
```rust
fn takes_u8(x: u8) {
// ...
}
fn main() {
for i in 0..256 {
println!("i: {}", i);
takes_u8(i);
}
}
```
What does this program do? The answer: nothing. The warning we get when
compiling has a hint:
```text
warning: literal out of range for u8
--> src/main.rs:6:17
|
6 | for i in 0..256 {
| ^^^
|
= note: #[warn(overflowing_literals)] on by default
```
Thats right, since `i` is a `u8`, this overflows, and is the same as writing
`for i in 0..0`, so the loop executes zero times.
We can do this with inclusive ranges, however:
```rust
fn takes_u8(x: u8) {
// ...
}
fn main() {
for i in 0..=255 {
println!("i: {}", i);
takes_u8(i);
}
}
```
This will produce those 256 lines of output you might have been expecting.

View File

@ -0,0 +1,6 @@
# Data types
[fis]: rust-2018/data-types/field-init-shorthand.html
In this chapter of the guide, we discuss a few improvements to data types.
One of these are [field-init-shorthand][fis].

View File

@ -0,0 +1,33 @@
# "Operator-equals" are now implementable
![Minimum Rust version: 1.8](https://img.shields.io/badge/Minimum%20Rust%20Version-1.8-brightgreen.svg)
The various “operator equals” operators, such as `+=` and `-=`, are
implementable via various traits. For example, to implement `+=` on
a type of your own:
```rust
use std::ops::AddAssign;
#[derive(Debug)]
struct Count {
value: i32,
}
impl AddAssign for Count {
fn add_assign(&mut self, other: Count) {
self.value += other.value;
}
}
fn main() {
let mut c1 = Count { value: 1 };
let c2 = Count { value: 5 };
c1 += c2;
println!("{:?}", c1);
}
```
This will print `Count { value: 6 }`.

View File

@ -0,0 +1,60 @@
# `union` for an unsafe form of `enum`
![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg)
Rust now supports `unions`:
```rust
union MyUnion {
f1: u32,
f2: f32,
}
```
Unions are kind of like enums, but they are “untagged”. Enums have a “tag”
that stores which variant is the correct one at runtime; unions don't have
this tag.
Since we can interpret the data held in the union using the wrong variant and
Rust cant check this for us, that means reading a unions field is unsafe:
```rust
# union MyUnion {
# f1: u32,
# f2: f32,
# }
let mut u = MyUnion { f1: 1 };
u.f1 = 5;
let value = unsafe { u.f1 };
```
Pattern matching works too:
```rust
# union MyUnion {
# f1: u32,
# f2: f32,
# }
fn f(u: MyUnion) {
unsafe {
match u {
MyUnion { f1: 10 } => { println!("ten"); }
MyUnion { f2 } => { println!("{}", f2); }
}
}
}
```
When are unions useful? One major use-case is interoperability with C. C APIs
can (and depending on the area, often do) expose unions, and so this makes
writing API wrappers for those libraries significantly easier. Additionally,
unions also simplify Rust implementations of space-efficient or
cache-efficient structures relying on value representation, such as
machine-word-sized unions using the least-significant bits of aligned
pointers to distinguish cases.
Theres still more improvements to come. For now, unions can only include
`Copy` types and may not implement `Drop`. We expect to lift these
restrictions in the future.

View File

@ -0,0 +1,6 @@
# Documentation
[sec_ed]: rust-2018/documentation/new-editions-of-the-book.html
In this chapter of the guide, we discuss a few improvements to documentation.
A notable addition here is the [second edition of "the book"][sec_ed].

View File

@ -0,0 +1,37 @@
# New editions of the "the book"
![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) for drafts of the second edition
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) for the final version of the second edition
![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition
We've distributed a copy of "The Rust Programming Language," affectionately
nicknamed "the book", with every version of Rust since Rust 1.0.
However, because it was written before Rust 1.0, it started showing its age.
Many parts of the book are vague, because it was written before the true
details were nailed down for the 1.0 release. It didn't do a fantastic job of
teaching lifetimes.
Starting with Rust 1.18, we shipped drafts of a second edition of the book.
The final version was shipped with Rust 1.26. The new edition is a complete
re-write from the ground up, using the last two years of knowledge weve
gained from teaching people Rust. Youll find brand-new explanations for a
lot of Rusts core concepts, new projects to build, and all kinds of other
good stuff. Please [check it
out](https://doc.rust-lang.org/book/second-edition/index.html) and let us
know what you think!
You can also purchase [a dead-tree version from No Starch
Press](https://nostarch.com/Rust). Now that the print version has shipped,
the second edition is frozen.
The names are a bit confusing though, because the "second edition" of the
book is the first printed edition of the book. As such, we decided that newer
editions of the book will correspond with newer editions of Rust itself, and
so starting with 1.28, we've been shipping drafts of the next version, [the
2018 Edition](https://doc.rust-lang.org/book/2018-edition/index.html). It's
still pretty close to the second edition, but contains information about
newer features since the book's content was frozen. We'll be continuing to
update this edition until we decide to print a second edition in paper.

View File

@ -0,0 +1,11 @@
# `std::os` has documentation for all platforms
![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg)
The `std::os` module contains operating system specific functionality. Youll
now see more than just linux, the platform we build the documentation on.
Weve long regretted that the hosted version of the documentation has been
Linux-specific; this is a first step towards rectifying that. This is
specific to the standard library and not for general use; we hope to improve
this further in the future.

View File

@ -0,0 +1,33 @@
# The Rust Bookshelf
![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg), each book is different.
As Rust's documentation has grown, we've gained far more than just "The book"
and the reference. We now have a collection of various long-form docs,
nicknamed "the Rust Bookshelf." Different resources are added at various
times, and we're adding new ones as more get written.
## The Cargo book
![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg)
Historically, Cargos docs were hosted on <http://doc.crates.io>, which
doesnt follow the release train model, even though Cargo itself does. This
led to situations where a feature would land in Cargo nightly, the docs would
be updated, and then for up to twelve weeks, users would think that it should
work, but it wouldnt yet. <https://doc.rust-lang.org/cargo> is the new home
of Cargos docs, and <http://doc.crates.io> now redirects there.
## The `rustdoc` book
![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg)
Rustdoc, our documentation tool, now has a guide at <https://doc.rust-lang.org/rustdoc>.
## Rust By Example
![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg)
Rust by Example used to live at <https://rustbyexample.com>, but now is part of the Bookshelf!
It can be found at <https://doc.rust-lang.org/rust-by-example/>. RBE lets you learn Rust through
short code examples and exercises, as opposed to the lengthy prose of The Book.

View File

@ -0,0 +1,10 @@
# The Rustonomicon
![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.3-brightgreen.svg)
We now have a draft book, [The Rustonomicon: the Dark Arts of Advanced and
Unsafe Rust Programming](https://doc.rust-lang.org/stable/nomicon/).
From the title, I'm sure you can guess: this book discusses some advanced
topics, including `unsafe`. It's a must-read for anyone who's working at the
lowest levels with Rust.

View File

@ -0,0 +1,18 @@
# Aborting on panic
![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg)
By default, Rust programs will unwind the stack when a `panic!` happens. If you'd prefer an
immediate abort instead, you can configure this in `Cargo.toml`:
```toml
[profile.debug]
panic = "abort"
[profile.release]
panic = "abort"
```
Why might you choose to do this? By removing support for unwinding, you'll
get smaller binaries. You will lose the ability to catch panics. Which choice
is right for you depends on exactly what you're doing.

View File

@ -0,0 +1,80 @@
# Controlling panics with `std::panic`
![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg)
There is a `std::panic` module, which includes methods for halting the
unwinding process started by a panic:
```rust
use std::panic;
let result = panic::catch_unwind(|| {
println!("hello!");
});
assert!(result.is_ok());
let result = panic::catch_unwind(|| {
panic!("oh no!");
});
assert!(result.is_err());
```
In general, Rust distinguishes between two ways that an operation can fail:
- Due to an *expected problem*, like a file not being found.
- Due to an *unexpected problem*, like an index being out of bounds for an array.
Expected problems usually arise from conditions that are outside of your
control; robust code should be prepared for anything its environment might throw
at it. In Rust, expected problems are handled via [the `Result` type][result],
which allows a function to return information about the problem to its caller,
which can then handle the error in a fine-grained way.
[result]: http://doc.rust-lang.org/std/result/index.html
Unexpected problems are *bugs*: they arise due to a contract or assertion being
violated. Since they are unexpected, it doesn't make sense to handle them in a
fine-grained way. Instead, Rust employs a "fail fast" approach by *panicking*,
which by default unwinds the stack (running destructors but no other code) of
the thread which discovered the error. Other threads continue running, but will
discover the panic any time they try to communicate with the panicked thread
(whether through channels or shared memory). Panics thus abort execution up to
some "isolation boundary", with code on the other side of the boundary still
able to run, and perhaps to "recover" from the panic in some very coarse-grained
way. A server, for example, does not necessarily need to go down just because of
an assertion failure in one of its threads.
It's also worth noting that programs may choose to *abort* instead of unwind,
and so catching panics may not work. If your code relies on `catch_unwind`, you
should add this to your Cargo.toml:
```toml
[profile.debug]
panic = "unwind"
[profile.release]
panic = "unwind"
```
If any of your users choose to abort, they'll get a compile-time failure.
The `catch_unwind` API offers a way to introduce new isolation boundaries
*within a thread*. There are a couple of key motivating examples:
* Embedding Rust in other languages
* Abstractions that manage threads
* Test frameworks, because tests may panic and you don't want that to kill the test runner
For the first case, unwinding across a language boundary is undefined behavior,
and often leads to segfaults in practice. Allowing panics to be caught means
that you can safely expose Rust code via a C API, and translate unwinding into
an error on the C side.
For the second case, consider a threadpool library. If a thread in the pool
panics, you generally don't want to kill the thread itself, but rather catch the
panic and communicate it to the client of the pool. The `catch_unwind` API is
paired with `resume_unwind`, which can then be used to restart the panicking
process on the client of the pool, where it belongs.
In both cases, you're introducing a new isolation boundary within a thread, and
then translating the panic into some other form of error elsewhere.

View File

@ -0,0 +1,6 @@
# Error handling and Panics
[qop]: rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.html
In this chapter of the guide, we discuss a few improvements to error handling
in Rust. The most notable of these is [the introduction of the `?` operator][qop].

View File

@ -0,0 +1,129 @@
# `?` in `main` and tests
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
Rust's error handling revolves around returning `Result<T, E>` and using `?`
to propagate errors. For those who write many small programs and, hopefully,
many tests, one common paper cut has been mixing entry points such as `main`
and `#[test]`s with error handling.
As an example, you might have tried to write:
```rust,ignore
use std::fs::File;
fn main() {
let f = File::open("bar.txt")?;
}
```
Since `?` works by propagating the `Result` with an early return to the
enclosing function, the snippet above does not work, and results today
in the following error:
```rust,ignore
error[E0277]: the `?` operator can only be used in a function that returns `Result`
or `Option` (or another type that implements `std::ops::Try`)
--> src/main.rs:5:13
|
5 | let f = File::open("bar.txt")?;
| ^^^^^^^^^^^^^^^^^^^^^^ cannot use the `?` operator in a function that returns `()`
|
= help: the trait `std::ops::Try` is not implemented for `()`
= note: required by `std::ops::Try::from_error`
```
To solve this problem in Rust 2015, you might have written something like:
```rust
// Rust 2015
# use std::process;
# use std::error::Error;
fn run() -> Result<(), Box<Error>> {
// real logic..
Ok(())
}
fn main() {
if let Err(e) = run() {
println!("Application error: {}", e);
process::exit(1);
}
}
```
However, in this case, the `run` function has all the interesting logic and
`main` is just boilerplate. The problem is even worse for `#[test]`s, since
there tend to be a lot more of them.
In Rust 2018 you can instead let your `#[test]`s and `main` functions return
a `Result`:
```rust,no_run
// Rust 2018
use std::fs::File;
fn main() -> Result<(), std::io::Error> {
let f = File::open("bar.txt")?;
Ok(())
}
```
In this case, if say the file doesn't exist and there is an `Err(err)` somewhere,
then `main` will exit with an error code (not `0`) and print out a `Debug`
representation of `err`.
## More details
Getting `-> Result<..>` to work in the context of `main` and `#[test]`s is not
magic. It is all backed up by a `Termination` trait which all valid return
types of `main` and testing functions must implement. The trait is defined as:
```rust
pub trait Termination {
fn report(self) -> i32;
}
```
When setting up the entry point for your application, the compiler will use this
trait and call `.report()` on the `Result` of the `main` function you have written.
Two simplified example implementations of this trait for `Result` and `()` are:
```rust
# #![feature(process_exitcode_placeholder, termination_trait_lib)]
# use std::process::ExitCode;
# use std::fmt;
#
# pub trait Termination { fn report(self) -> i32; }
impl Termination for () {
fn report(self) -> i32 {
# use std::process::Termination;
ExitCode::SUCCESS.report()
}
}
impl<E: fmt::Debug> Termination for Result<(), E> {
fn report(self) -> i32 {
match self {
Ok(()) => ().report(),
Err(err) => {
eprintln!("Error: {:?}", err);
# use std::process::Termination;
ExitCode::FAILURE.report()
}
}
}
}
```
As you can see in the case of `()`, a success code is simply returned.
In the case of `Result`, the success case delegates to the implementation for
`()` but prints out an error message and a failure exit code on `Err(..)`.
To learn more about the finer details, consult either [the tracking issue](https://github.com/rust-lang/rust/issues/43301) or [the RFC](https://github.com/rust-lang/rfcs/blob/master/text/1937-ques-in-main.md).

View File

@ -0,0 +1,120 @@
# The `?` operator for easier error handling
![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) for `Result<T, E>`
![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) for `Option<T>`
Rust has gained a new operator, `?`, that makes error handling more pleasant
by reducing the visual noise involved. It does this by solving one simple
problem. To illustrate, imagine we had some code to read some data from a
file:
```rust
# use std::{io::{self, prelude::*}, fs::File};
fn read_username_from_file() -> Result<String, io::Error> {
let f = File::open("username.txt");
let mut f = match f {
Ok(file) => file,
Err(e) => return Err(e),
};
let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}
```
> Note: this code could be made simpler with a single call to
> [`std::fs::read_to_string`](https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html),
> but we're writing it all out manually here to have an example with multiple
> errors.
This code has two paths that can fail, opening the file and reading the data
from it. If either of these fail to work, we'd like to return an error from
`read_username_from_file`. Doing so involves `match`ing on the result of the
I/O operations. In simple cases like this though, where we are only
propagating errors up the call stack, the matching is just boilerplate -
seeing it written out, in the same pattern every time, doesn't provide the
reader with a great deal of useful information.
With `?`, the above code looks like this:
```rust
# use std::{io::{self, prelude::*}, fs::File};
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("username.txt")?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}
```
The `?` is shorthand for the entire match statements we wrote earlier. In
other words, `?` applies to a `Result` value, and if it was an `Ok`, it
unwraps it and gives the inner value. If it was an `Err`, it returns from the
function you're currently in. Visually, it is much more straightforward.
Instead of an entire match statement, now we are just using the single "?"
character to indicate that here we are handling errors in the standard way,
by passing them up the call stack.
Seasoned Rustaceans may recognize that this is the same as the `try!` macro
that's been available since Rust `1.0`. And indeed, they are the same.
Previously, `read_username_from_file` could have been implemented like this:
```rust
# use std::{io::{self, prelude::*}, fs::File};
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = try!(File::open("username.txt"));
let mut s = String::new();
try!(f.read_to_string(&mut s));
Ok(s)
}
```
So why extend the language when we already have a macro? There are multiple
reasons. First, `try!` has proved to be extremely useful, and is used often
in idiomatic Rust. It is used so often that we think it's worth having a
sweet syntax. This sort of evolution is one of the great advantages of a
powerful macro system: speculative extensions to the language syntax can be
prototyped and iterated on without modifying the language itself, and in
return, macros that turn out to be especially useful can indicate missing
language features. This evolution, from `try!` to `?` is a great example.
One of the reasons `try!` needs a sweeter syntax is that it is quite
unattractive when multiple invocations of `try!` are used in succession.
Consider:
```rust,ignore
try!(try!(try!(foo()).bar()).baz())
```
as opposed to
```rust,ignore
foo()?.bar()?.baz()?
```
The first is quite difficult to scan visually, and each layer of error
handling prefixes the expression with an additional call to `try!`. This
brings undue attention to the trivial error propagation, obscuring the main
code path, in this example the calls to `foo`, `bar` and `baz`. This sort of
method chaining with error handling occurs in situations like the builder
pattern.
Finally, the dedicated syntax will make it easier in the future to produce
nicer error messages tailored specifically to `?`, whereas it is difficult to
produce nice errors for macro-expanded code generally.
You can use `?` with `Result<T, E>`s, but also with `Option<T>`. In that
case, `?` will return a value for `Some(T)` and return `None` for `None`. One
current restriction is that you cannot use `?` for both in the same function,
as the return type needs to match the type you use `?` on. In the future,
this restriction will be lifted.

View File

@ -0,0 +1,8 @@
# Rust 2018
The edition system was created for the release of Rust 2018. The theme of Rust 2018
is *productivity*. Rust 2018 improves upon Rust 2015 through new features,
simpler syntax in some cases, a smarter borrow-checker, and a host of other things.
These are all in service of the productivity goal. Rust 2015 was a foundation;
Rust 2018 smooths off rough edges, makes writing code simpler and easier,
and removes some inconsistencies.

View File

@ -0,0 +1,38 @@
# At most one repetition
In Rust 2018, we have made a couple of changes to the macros-by-example syntax.
1. We have added a new Kleene operator `?` which means "at most one"
repetition. This operator does not accept a separator token.
2. We have disallowed using `?` as a separator to remove ambiguity with `?`.
For example, consider the following Rust 2015 code:
```rust2018
macro_rules! foo {
($a:ident, $b:expr) => {
println!("{}", $a);
println!("{}", $b);
}
($a:ident) => {
println!("{}", $a);
}
}
```
Macro `foo` can be called with 1 or 2 arguments; the second one is optional,
but you need a whole other matcher to represent this possibility. This is
annoying if your matchers are long. In Rust 2018, one can simply write the
following:
```rust2018
macro_rules! foo {
($a:ident $(, $b:expr)?) => {
println!("{}", $a);
$(
println!("{}", $b);
)?
}
}
```

View File

@ -0,0 +1,49 @@
# Custom Derive
![Minimum Rust version: 1.15](https://img.shields.io/badge/Minimum%20Rust%20Version-1.15-brightgreen.svg)
In Rust, youve always been able to automatically implement some traits
through the derive attribute:
```rust
#[derive(Debug)]
struct Pet {
name: String,
}
```
The `Debug` trait is then implemented for `Pet`, with vastly less boilerplate. For example, without `derive`, you'd have
to write this:
```rust
use std::fmt;
struct Pet {
name: String,
}
impl fmt::Debug for Pet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Pet { name } => {
let mut debug_trait_builder = f.debug_struct("Pet");
let _ = debug_trait_builder.field("name", name);
debug_trait_builder.finish()
}
}
}
}
```
Whew!
However, this only worked for traits provided as part of the standard
library; it was not customizable. But now, you can tell Rust what to do when
someone wants to derive your trait. This is used heavily in popular crates
like [serde](https://serde.rs/) and [Diesel](http://diesel.rs/).
For more, including learning how to build your own custom derive, see [The
Rust Programming
Language](https://doc.rust-lang.org/book/second-edition/appendix-04-macros.html#procedural-macros-for-custom-derive).

View File

@ -0,0 +1,6 @@
# Macros
[custom-derive]: rust-2018/macros/custom-derive.html
In this chapter of the guide, we discuss a few improvements to the macro system.
A notable addition here is the introduction of [custom derive macros][custom-derive].

View File

@ -0,0 +1,271 @@
# Macro changes
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
## `macro_rules!` style macros
In Rust 2018, you can import specific macros from external crates via `use`
statements, rather than the old `#[macro_use]` attribute.
For example, consider a `bar` crate that implements a `baz!` macro. In
`src/lib.rs`:
```rust
#[macro_export]
macro_rules! baz {
() => ()
}
```
In your crate, you would have written
```rust,ignore
// Rust 2015
#[macro_use]
extern crate bar;
fn main() {
baz!();
}
```
Now, you write:
```rust,ignore
// Rust 2018
use bar::baz;
fn main() {
baz!();
}
```
This moves `macro_rules` macros to be a bit closer to other kinds of items.
Note that you'll still need `#[macro_use]` to use macros you've defined
in your own crate; this feature only works for importing macros from
external crates.
## Procedural macros
When using procedural macros to derive traits, you will have to name the macro
that provides the custom derive. This generally matches the name of the trait,
but check with the documentation of the crate providing the derives to be sure.
For example, with Serde you would have written
```rust,ignore
// Rust 2015
extern crate serde;
#[macro_use] extern crate serde_derive;
#[derive(Serialize, Deserialize)]
struct Bar;
```
Now, you write instead:
```rust,ignore
// Rust 2018
use serde_derive::{Serialize, Deserialize};
#[derive(Serialize, Deserialize)]
struct Bar;
```
## More details
This only works for macros defined in external crates.
For macros defined locally, `#[macro_use] mod foo;` is still required, as it was in Rust 2015.
### Local helper macros
Sometimes it is helpful or necessary to have helper macros inside your module. This can make
supporting both versions of rust more complicated.
For example, let's make a simplified (and slightly contrived) version of the `log` crate in 2015
edition style:
```rust
use std::fmt;
/// How important/severe the log message is.
#[derive(Copy, Clone)]
pub enum LogLevel {
Warn,
Error
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LogLevel::Warn => write!(f, "warning"),
LogLevel::Error => write!(f, "error"),
}
}
}
// A helper macro to log the message.
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_log {
($level:expr, $msg:expr) => {{
println!("{}: {}", $level, $msg)
}}
}
/// Warn level log message
#[macro_export]
macro_rules! warn {
($($args:tt)*) => {
__impl_log!($crate::LogLevel::Warn, format_args!($($args)*))
}
}
/// Error level log message
#[macro_export]
macro_rules! error {
($($args:tt)*) => {
__impl_log!($crate::LogLevel::Error, format_args!($($args)*))
}
}
```
Our `__impl_log!` macro is private to our module, but needs to be exported as it is called by other
macros, and in 2015 edition all used macros must be exported.
Now, in 2018 this example will not compile:
```rust,ignore
use log::error;
fn main() {
error!("error message");
}
```
will give an error message about not finding the `__impl_log!` macro. This is because unlike in
the 2015 edition, macros are namespaced and we must import them. We could do
```rust,ignore
use log::{__impl_log, error};
```
which would make our code compile, but `__impl_log` is meant to be an implementation detail!
#### Macros with `$crate::` prefix.
The cleanest way to handle this situation is to use the `$crate::` prefix for macros, the same as
you would for any other path. Versions of the compiler >= 1.30 will handle this in both editions:
```rust
macro_rules! warn {
($($args:tt)*) => {
$crate::__impl_log!($crate::LogLevel::Warn, format_args!($($args)*))
}
}
// ...
```
However, this will not work for older versions of the compiler that don't understand the
`$crate::` prefix for macros.
#### Macros using `local_inner_macros`
We also have the `local_inner_macros` modifier that we can add to our `#[macro_export]` attribute.
This has the advantage of working with older rustc versions (older versions just ignore the extra
modifier). The downside is that it's a bit messier:
```rust,ignore
#[macro_export(local_inner_macros)]
macro_rules! warn {
($($args:tt)*) => {
__impl_log!($crate::LogLevel::Warn, format_args!($($args)*))
}
}
```
So the code knows to look for any macros used locally. But wait - this won't compile, because we
use the `format_args!` macro that isn't in our local crate (hence the convoluted example). The
solution is to add a level of indirection: we create a macro that wraps `format_args`, but is local
to our crate. That way everything works in both editions (sadly we have to pollute the global
namespace a bit, but that's ok).
```rust
// I've used the pattern `_<my crate name>__<macro name>` to name this macro, hopefully avoiding
// name clashes.
#[doc(hidden)]
#[macro_export]
macro_rules! _log__format_args {
($($inner:tt)*) => {
format_args! { $($inner)* }
}
}
```
Here we're using the most general macro pattern possible, a list of token trees. We just pass
whatever tokens we get to the inner macro, and rely on it to report errors.
So the full 2015/2018 working example would be:
```rust
use std::fmt;
/// How important/severe the log message is.
#[derive(Debug, Copy, Clone)]
pub enum LogLevel {
Warn,
Error
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
LogLevel::Warn => write!(f, "warning"),
LogLevel::Error => write!(f, "error"),
}
}
}
// A helper macro to log the message.
#[doc(hidden)]
#[macro_export]
macro_rules! __impl_log {
($level:expr, $msg:expr) => {{
println!("{}: {}", $level, $msg)
}}
}
/// Warn level log message
#[macro_export(local_inner_macros)]
macro_rules! warn {
($($args:tt)*) => {
__impl_log!($crate::LogLevel::Warn, _log__format_args!($($args)*))
}
}
/// Error level log message
#[macro_export(local_inner_macros)]
macro_rules! error {
($($args:tt)*) => {
__impl_log!($crate::LogLevel::Error, _log__format_args!($($args)*))
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! _log__format_args {
($($inner:tt)*) => {
format_args! { $($inner)* }
}
}
```
Once everyone is using a rustc version >= 1.30, we can all just use the `$crate::` method (2015
crates are guaranteed to carry on compiling fine with later versions of the compiler). We need to
wait for package managers and larger organisations to update their compilers before this happens,
so in the mean time we can use the `local_inner_macros` method to support everybody. :)

View File

@ -0,0 +1,6 @@
# Module system
[path clarity changes]: rust-2018/module-system/path-clarity.html
In this chapter of the guide, we discuss a few changes to the module system.
The most notable of these are the [path clarity changes].

View File

@ -0,0 +1,16 @@
# More visibility modifiers
![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-brightgreen.svg)
You can use the `pub` keyword to make something a part of a module's public interface. But in
addition, there are some new forms:
```rust,ignore
pub(crate) struct Foo;
pub(in a::b::c) struct Bar;
```
The first form makes the `Foo` struct public to your entire crate, but not
externally. The second form is similar, but makes `Bar` public for one other
module, `a::b::c` in this case.

View File

@ -0,0 +1,35 @@
# Nested imports with `use`
![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg)
A new way to write `use` statements has been added to Rust: nested import
groups. If youve ever written a set of imports like this:
```rust
use std::fs::File;
use std::io::Read;
use std::path::{Path, PathBuf};
```
You can now write this:
```rust
# mod foo {
// on one line
use std::{fs::File, io::Read, path::{Path, PathBuf}};
# }
# mod bar {
// with some more breathing room
use std::{
fs::File,
io::Read,
path::{
Path,
PathBuf
}
};
# }
```
This can reduce some repetition, and make things a bit more clear.

View File

@ -0,0 +1,390 @@
# Path clarity
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for "uniform paths"
The module system is often one of the hardest things for people new to Rust. Everyone
has their own things that take time to master, of course, but there's a root
cause for why it's so confusing to many: while there are simple and
consistent rules defining the module system, their consequences can feel
inconsistent, counterintuitive and mysterious.
As such, the 2018 edition of Rust introduces a few new module system
features, but they end up *simplifying* the module system, to make it more
clear as to what is going on.
Here's a brief summary:
* `extern crate` is no longer needed in 99% of circumstances.
* The `crate` keyword refers to the current crate.
* Absolute paths begin with a crate name, where the keyword `crate`
refers to the current crate.
* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed
when placing submodules in a subdirectory.
These may seem like arbitrary new rules when put this way, but the mental
model is now significantly simplified overall. Read on for more details!
> Additionally, in nightly, there's an additional possible tweak to paths
> called "Uniform paths". This is backwards compatible with the new path
> changes. Uniform paths have a dedicated section at the end of this guide.
## More details
Let's talk about each new feature in turn.
### No more `extern crate`
This one is quite straightforward: you no longer need to write `extern crate` to
import a crate into your project. Before:
```rust,ignore
// Rust 2015
extern crate futures;
mod submodule {
use futures::Future;
}
```
After:
```rust,ignore
// Rust 2018
mod submodule {
use futures::Future;
}
```
Now, to add a new crate to your project, you can add it to your `Cargo.toml`,
and then there is no step two. If you're not using Cargo, you already had to pass
`--extern` flags to give `rustc` the location of external crates, so you'd just
keep doing what you were doing there as well.
> One small note here: `cargo fix` will not currently automate this change. We may
> have it do this for you in the future.
#### An exception
There's one exception to this rule, and that's the "sysroot" crates. These are the
crates distributed with Rust itself. We'd eventually like to remove the requirement
for `extern crate` for them as well, but it hasn't shipped yet.
You'll need to use `extern crate` for:
* `proc_macro`
Additionally, you would need to use it for:
* `core`
* `std`
However, `extern crate std;` is already implicit, and with `#![no_std]`,
`extern crate core;` is already implicit. You'll only need these in highly
specialized situations.
Finally, on nightly, you'll need it for crates like:
* `alloc`
* `test`
#### Macros
One other use for `extern crate` was to import macros; that's no longer needed.
Check [the macro section](rust-2018/macros/macro-changes.html) for more.
If you've been using `as` to rename your crate like this:
```rust,ignore
extern crate futures as f;
use f::Future;
```
then removing the `extern crate` line on its own won't work. You'll need to do this:
```rust,ignore
use futures as f;
use self::f::Future;
```
This change will need to happen in any module that uses `f`.
### The `crate` keyword refers to the current crate.
In `use` declarations and in other code, you can refer to the root of the
current crate with the `crate::` prefix. For instance, `crate::foo::bar` will
always refer to the name `bar` inside the module `foo`, from anywhere else in
the same crate.
The prefix `::` previously referred to either the crate root or an external
crate; it now unambiguously refers to an external crate. For instance,
`::foo::bar` always refers to the name `bar` inside the external crate `foo`.
### Changes to paths
In Rust 2018, paths in `use` declarations *must* begin with a crate name,
`crate`, `self`, or `super`.
Code that looked like this:
```rust,ignore
// Rust 2015
extern crate futures;
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
```
Now looks like this:
```rust,ignore
// Rust 2018
// 'futures' is the name of a crate
use futures::Future;
mod foo {
pub struct Bar;
}
// 'crate' means the current crate
use crate::foo::Bar;
```
In addition, all of these path forms are available outside of `use`
declarations as well, which eliminates many sources of confusion. Consider
this code in Rust 2015:
```rust,ignore
// Rust 2015
extern crate futures;
mod submodule {
// this works!
use futures::Future;
// so why doesn't this work?
fn my_poll() -> futures::Poll { ... }
}
fn main() {
// this works
let five = std::sync::Arc::new(5);
}
mod submodule {
fn function() {
// ... so why doesn't this work
let five = std::sync::Arc::new(5);
}
}
```
> In real code, you couldn't repeat `mod submodule`, and `function` would be defined
> in the first `mod` block.
In the `futures` example, the `my_poll` function signature is incorrect,
because `submodule` contains no items named `futures`; that is, this path is
considered relative. `use futures::` works even though a lone `futures::`
doesn't! With `std` it can be even more confusing, as you never wrote the
`extern crate std;` line at all. So why does it work in `main` but not in a
submodule? Same thing: it's a relative path because it's not in a `use`
declaration. `extern crate std;` is inserted at the crate root, so it's fine
in `main`, but it doesn't exist in the submodule at all.
Let's look at how this change affects things:
```rust,ignore
// Rust 2018
// no more `extern crate futures;`
mod submodule {
// 'futures' is the name of a crate, so this works
use futures::Future;
// 'futures' is the name of a crate, so this works
fn my_poll<T, E>() -> futures::Poll {
unimplemented!()
}
fn function() {
// 'std' is the name of a crate, so this works
let five = std::sync::Arc::new(5);
}
}
fn main() {
// 'std' is the name of a crate, so this works
let five = std::sync::Arc::new(5);
}
```
Much more straightforward.
### No more `mod.rs`
In Rust 2015, if you have a submodule:
```rust,ignore
/// foo.rs
/// or
/// foo/mod.rs
mod foo;
```
It can live in `foo.rs` or `foo/mod.rs`. If it has submodules of its own, it
*must* be `foo/mod.rs`. So a `bar` submodule of `foo` would live at
`foo/bar.rs`.
In Rust 2018, `mod.rs` is no longer needed.
```rust,ignore
/// foo.rs
/// foo/bar.rs
mod foo;
/// in foo.rs
mod bar;
```
`foo.rs` can just be `foo.rs`,
and the submodule is still `foo/bar.rs`. This eliminates the special
name, and if you have a bunch of files open in your editor, you can clearly
see their names, instead of having a bunch of tabs named `mod.rs`.
# Uniform paths
> Uniform paths are a nightly-only feature.
The uniform paths variant of Rust 2018 simplifies and unifies path handling
compared to Rust 2015. In Rust 2015, paths work differently in `use`
declarations than they do elsewhere. In particular, paths in `use`
declarations would always start from the crate root, while paths in other code
implicitly started from the current module. Those differences didn't have any
effect in the top-level module, which meant that everything would seem
straightforward until working on a project large enough to have submodules.
In the uniform paths variant of Rust 2018, paths in `use` declarations and in
other code always work the same way, both in the top-level module and in any
submodule. You can always use a relative path from the current module, a path
starting from an external crate name, or a path starting with `crate`, `super`,
or `self`.
Code that looked like this:
```rust,ignore
// Rust 2015
extern crate futures;
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
fn my_poll() -> futures::Poll { ... }
enum SomeEnum {
V1(usize),
V2(String),
}
fn func() {
let five = std::sync::Arc::new(5);
use SomeEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
```
will look exactly the same in Rust 2018, except that you can delete the `extern
crate` line:
```rust,ignore
// Rust 2018 (uniform paths variant)
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
fn my_poll() -> futures::Poll { ... }
enum SomeEnum {
V1(usize),
V2(String),
}
fn func() {
let five = std::sync::Arc::new(5);
use SomeEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
```
With Rust 2018, however, the same code will also work completely unmodified in
a submodule:
```rust,ignore
// Rust 2018 (uniform paths variant)
mod submodule {
use futures::Future;
mod foo {
pub struct Bar;
}
use foo::Bar;
fn my_poll() -> futures::Poll { ... }
enum SomeEnum {
V1(usize),
V2(String),
}
fn func() {
let five = std::sync::Arc::new(5);
use SomeEnum::*;
match ... {
V1(i) => { ... }
V2(s) => { ... }
}
}
}
```
This makes it easy to move code around in a project, and avoids introducing
additional complexity to multi-module projects.
If a path is ambiguous, such as if you have an external crate and a local
module or item with the same name, you'll get an error, and you'll need to
either rename one of the conflicting names or explicitly disambiguate the path.
To explicitly disambiguate a path, use `::name` for an external crate name, or
`self::name` for a local module or item.

View File

@ -0,0 +1,68 @@
# Raw identifiers
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
Rust, like many programming languages, has the concept of "keywords".
These identifiers mean something to the language, and so you cannot use them in
places like variable names, function names, and other places.
Raw identifiers let you use keywords where they would not normally be allowed.
For example, `match` is a keyword. If you try to compile this function:
```rust,ignore
fn match(needle: &str, haystack: &str) -> bool {
haystack.contains(needle)
}
```
You'll get this error:
```text
error: expected identifier, found keyword `match`
--> src/main.rs:4:4
|
4 | fn match(needle: &str, haystack: &str) -> bool {
| ^^^^^ expected identifier, found keyword
```
You can write this with a raw identifier:
```rust
fn r#match(needle: &str, haystack: &str) -> bool {
haystack.contains(needle)
}
fn main() {
assert!(r#match("foo", "foobar"));
}
```
Note the `r#` prefix on both the function name as well as the call.
## Motivation
This feature is useful for a few reasons, but the primary motivation was
inter-edition situations. For example, `try` is not a keyword in the 2015
edition, but is in the 2018 edition. So if you have a library that is written
in Rust 2015 and has a `try` function, to call it in Rust 2018, you'll need
to use the raw identifier.
## New keywords
The new confirmed keywords in edition 2018 are:
### `async` and `await`
[RFC 2394]: https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#final-syntax-for-the-await-expression
Here, `async` is reserved for use in `async fn` as well as in `async ||` closures and
`async { .. }` blocks. Meanwhile, `await` is reserved to keep our options open
with respect to `await!(expr)` syntax. See [RFC 2394] for more details.
### `try`
[RFC 2388]: https://github.com/rust-lang/rfcs/pull/2388
The `do catch { .. }` blocks have been renamed to `try { .. }` and to support
that, the keyword `try` is reserved in edition 2018.
See [RFC 2388] for more details.

View File

@ -0,0 +1,61 @@
# Default match bindings
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
Have you ever had a borrowed `Option<T>` and tried to match on it? You
probably wrote this:
```rust,ignore
let s: &Option<String> = &Some("hello".to_string());
match s {
Some(s) => println!("s is: {}", s),
_ => (),
};
```
In Rust 2015, this would fail to compile, and you would have to write the
following instead:
```rust,ignore
// Rust 2015
let s: &Option<String> = &Some("hello".to_string());
match s {
&Some(ref s) => println!("s is: {}", s),
_ => (),
};
```
Rust 2018, by contrast, will infer the `&`s and `ref`s, and your original
code will Just Work.
This affects not just `match`, but patterns everywhere, such as in `let`
statements, closure arguments, and `for` loops.
## More details
The mental model of patterns has shifted a bit with this change, to bring it
into line with other aspects of the language. For example, when writing a
`for` loop, you can iterate over borrowed contents of a collection by
borrowing the collection itself:
```rust,ignore
let my_vec: Vec<i32> = vec![0, 1, 2];
for x in &my_vec { ... }
```
The idea is that an `&T` can be understood as a *borrowed view of `T`*, and
so when you iterate, match, or otherwise destructure a `&T` you get a
borrowed view of its internals as well.
More formally, patterns have a "binding mode," which is either by value
(`x`), by reference (`ref x`), or by mutable reference (`ref mut x`). In Rust
2015, `match` always started in by-value mode, and required you to explicitly
write `ref` or `ref mut` in patterns to switch to a borrowing mode. In Rust
2018, the type of the value being matched informs the binding mode, so that
if you match against an `&Option<String>` with a `Some` variant, you are put
into `ref` mode automatically, giving you a borrowed view of the internal
data. Similarly, `&mut Option<String>` would give you a `ref mut` view.

View File

@ -0,0 +1,6 @@
# Ownership and lifetimes
[dmbm]: rust-2018/ownership-and-lifetimes/default-match-bindings.html
In this chapter of the guide, we discuss a few improvements to ownership and lifetimes.
One of the most notable of these is [default match binding modes][dmbm].

View File

@ -0,0 +1,72 @@
# `T: 'a` inference in structs
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
An annotation in the form of `T: 'a`, where `T` is either a type or another
lifetime, is called an *"outlives"* requirement. Note that *"outlives"* also
implies `'a: 'a`.
One way in which edition 2018 helps you out in maintaining flow when writing
programs is by removing the need to explicitly annotate these `T: 'a` outlives
requirements in `struct` definitions. Instead, the requirements will be
inferred from the fields present in the definitions.
Consider the following `struct` definitions in Rust 2015:
```rust
// Rust 2015
struct Ref<'a, T: 'a> {
field: &'a T
}
// or written with a `where` clause:
struct WhereRef<'a, T> where T: 'a {
data: &'a T
}
// with nested references:
struct RefRef<'a, 'b: 'a, T: 'b> {
field: &'a &'b T,
}
// using an associated type:
struct ItemRef<'a, T: Iterator>
where
T::Item: 'a
{
field: &'a T::Item
}
```
In Rust 2018, since the requirements are inferred, you can instead write:
```rust,ignore
// Rust 2018
struct Ref<'a, T> {
field: &'a T
}
struct WhereRef<'a, T> {
data: &'a T
}
struct RefRef<'a, 'b, T> {
field: &'a &'b T,
}
struct ItemRef<'a, T: Iterator> {
field: &'a T::Item
}
```
If you prefer to be more explicit in some cases, that is still possible.
## More details
For more details, see [the tracking issue](https://github.com/rust-lang/rust/issues/44493)
and [the RFC](https://github.com/rust-lang/rfcs/pull/2093).

View File

@ -0,0 +1,75 @@
# Lifetime elision in impl
![Minimum Rust version: 1.31](https://img.shields.io/badge/Minimum%20Rust%20Version-1.31-brightgreen.svg)
When writing `impl` blocks, you can now elide lifetime annotations in some
situations.
Consider a trait like `MyIterator`:
```rust,ignore
trait MyIterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
```
In Rust 2015, if we wanted to implement this iterator for mutable references
to `Iterators`, we'd need to write this:
```rust,ignore
impl<'a, I: MyIterator> MyIterator for &'a mut I {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
(*self).next()
}
}
```
Note all of the `'a` annotations. In Rust 2018, we can write this:
```rust,ignore
impl<I: MyIterator> MyIterator for &mut I {
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
(*self).next()
}
}
```
Similarly, lifetime annotations can appear due to a struct that contains
references:
```rust,ignore
struct SetOnDrop<'a, T> {
borrow: &'a mut T,
value: Option<T>,
}
```
In Rust 2015, to implement `Drop` on this struct, we'd write:
```rust,ignore
impl<'a, T> Drop for SetOnDrop<'a, T> {
fn drop(&mut self) {
if let Some(x) = self.value.take() {
*self.borrow = x;
}
}
}
```
But in Rust 2018, we can combine elision with [the anonymous lifetime] and
write this instead.
```rust,ignore
impl<T> Drop for SetOnDrop<'_, T> {
fn drop(&mut self) {
if let Some(x) = self.value.take() {
*self.borrow = x;
}
}
}
```
[the anonymous lifetime]: rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.html

View File

@ -0,0 +1,83 @@
# Non-lexical lifetimes
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
The borrow checker has been enhanced to accept more code, via a mechanism
called "non-lexical lifetimes." Consider this example:
```rust,ignore
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
}
```
In older Rust, this is a compile-time error:
```text
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:18
|
4 | let y = &x;
| - immutable borrow occurs here
5 | let z = &mut x;
| ^ mutable borrow occurs here
6 | }
| - immutable borrow ends here
```
This is because lifetimes follow "lexical scope"; that is, the borrow from `y` is
considered to be held until `y` goes out of scope at the end of `main`, even though
we never use `y` again. This code is fine, but the borrow checker could not handle it.
Today, this code will compile just fine.
## Better errors
What if we did use `y`, like this?
```rust,ignore
fn main() {
let mut x = 5;
let y = &x;
let z = &mut x;
println!("y: {}", y);
}
```
Here's the error:
```text
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:18
|
4 | let y = &x;
| - immutable borrow occurs here
5 | let z = &mut x;
| ^ mutable borrow occurs here
...
8 | }
| - immutable borrow ends here
```
With non-lexical lifetimes, the error changes slightly:
```text
error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
--> src/main.rs:5:13
|
4 | let y = &x;
| -- immutable borrow occurs here
5 | let z = &mut x;
| ^^^^^^ mutable borrow occurs here
6 |
7 | println!("y: {}", y);
| - borrow later used here
```
Instead of pointing to where `y` goes out of scope, it shows you where
the conflicting borrow occurs. This makes these sorts of errors *far* easier to debug.

View File

@ -0,0 +1,41 @@
# Simpler lifetimes in `static` and `const`
![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg)
In older Rust, you had to explicitly write the `'static` lifetime in any
`static` or `const` that needed a lifetime:
```rust
# mod foo {
const NAME: &'static str = "Ferris";
# }
# mod bar {
static NAME: &'static str = "Ferris";
# }
```
But `'static` is the only possible lifetime there. So Rust now assumes the `'static` lifetime,
and you don't have to write it out:
```rust
# mod foo {
const NAME: &str = "Ferris";
# }
# mod bar {
static NAME: &str = "Ferris";
# }
```
In some situations, this can remove a *lot* of boilerplate:
```rust
# mod foo {
// old
const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"];
# }
# mod bar {
// new
const NAMES: &[&str; 2] = &["Ferris", "Bors"];
# }
```

View File

@ -0,0 +1,103 @@
# `'_`, the anonymous lifetime
![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg)
Rust 2018 allows you to explicitly mark where a lifetime is elided, for types
where this elision might otherwise be unclear. To do this, you can use the
special lifetime `'_` much like you can explicitly mark that a type is inferred
with the syntax `let x: _ = ..;`.
Let's say, for whatever reason, that we have a simple wrapper around `&'a str`:
```rust
struct StrWrap<'a>(&'a str);
```
In Rust 2015, you might have written:
```rust
// Rust 2015
use std::fmt;
# struct StrWrap<'a>(&'a str);
fn make_wrapper(string: &str) -> StrWrap {
StrWrap(string)
}
impl<'a> fmt::Debug for StrWrap<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.write_str(self.0)
}
}
```
In Rust 2018, you can instead write:
```rust
#![feature(rust_2018_preview)]
# use std::fmt;
# struct StrWrap<'a>(&'a str);
// Rust 2018
fn make_wrapper(string: &str) -> StrWrap<'_> {
StrWrap(string)
}
impl fmt::Debug for StrWrap<'_> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt.write_str(self.0)
}
}
```
## More details
In the Rust 2015 snippet above, we've used `-> StrWrap`. However, unless you take
a look at the definition of `StrWrap`, it is not clear that the returned value
is actually borrowing something. Therefore, starting with Rust 2018, it is
deprecated to leave off the lifetime parameters for non-reference-types (types
other than `&` and `&mut`). Instead, where you previously wrote `-> StrWrap`,
you should now write `-> StrWrap<'_>`, making clear that borrowing is occurring.
What exactly does `'_` mean? It depends on the context!
In output contexts, as in the return type of `make_wrapper`,
it refers to a single lifetime for all "output" locations.
In input contexts, a fresh lifetime is generated for each "input location".
More concretely, to understand input contexts, consider the following example:
```rust
// Rust 2015
struct Foo<'a, 'b: 'a> {
field: &'a &'b str,
}
impl<'a, 'b: 'a> Foo<'a, 'b> {
// some methods...
}
```
We can rewrite this as:
```rust
#![feature(rust_2018_preview)]
# struct Foo<'a, 'b: 'a> {
# field: &'a &'b str,
# }
// Rust 2018
impl Foo<'_, '_> {
// some methods...
}
```
This is the same, because for each `'_`, a fresh lifetime is generated.
Finally, the relationship `'a: 'b` which the struct requires must be upheld.
For more details, see the [tracking issue on In-band lifetime bindings](https://github.com/rust-lang/rust/issues/44524).

View File

@ -0,0 +1,18 @@
# cdylib crates for C interoperability
![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg) for `rustc`
![Minimum Rust version: 1.11](https://img.shields.io/badge/Minimum%20Rust%20Version-1.11-brightgreen.svg) for `cargo`
If you're producing a library that you intend to be used from C (or another
language through a C FFI), there's no need for Rust to include Rust-specific
stuff in the final object code. For libraries like that, you'll want to use
the `cdylib` crate type in your `Cargo.toml`:
```toml
[lib]
crate-type = ["cdylib"]
```
This will produce a smaller binary, with no Rust-specific information inside
of it.

View File

@ -0,0 +1,35 @@
# Global allocators
![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-brightgreen.svg)
Allocators are the way that programs in Rust obtain memory from the system at
runtime. Previously, Rust did not allow changing the way memory is obtained,
which prevented some use cases. On some platforms, this meant using jemalloc,
on others, the system allocator, but there was no way for users to control
this key component. With 1.28.0, the `#[global_allocator]` attribute is now
stable, which allows Rust programs to set their allocator to the system
allocator, as well as define new allocators by implementing the `GlobalAlloc`
trait.
The default allocator for Rust programs on some platforms is jemalloc. The
standard library now provides a handle to the system allocator, which can be
used to switch to the system allocator when desired, by declaring a static
and marking it with the `#[global_allocator]` attribute.
```rust
use std::alloc::System;
#[global_allocator]
static GLOBAL: System = System;
fn main() {
let mut v = Vec::new();
// This will allocate memory using the system allocator.
v.push(1);
}
```
However, sometimes you want to define a custom allocator for a given
application domain. This is also relatively easy to do by implementing the
`GlobalAlloc` trait. You can read more about how to do this in [the
documentation](https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html).

View File

@ -0,0 +1,6 @@
# Platform and target support
[libcore]: rust-2018/platform-and-target-support/libcore-for-low-level-rust.html
In this chapter of the guide, we discuss a few improvements to platform and target support.
A notable addition to it was [that the `libcore` library now works on stable Rust][libcore].

View File

@ -0,0 +1,31 @@
# libcore for low-level Rust
![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg)
Rusts standard library is two-tiered: theres a small core library,
`libcore`, and the full standard library, `libstd`, that builds on top of it.
`libcore` is completely platform agnostic, and requires only a handful of
external symbols to be defined. Rusts `libstd` builds on top of `libcore`,
adding support for things like memory allocation and I/O. Applications using
Rust in the embedded space, as well as those writing operating systems, often
eschew `libstd`, using only `libcore`.
As an additional note, while building *libraries* with `libcore` is supported
today, building full applications is not yet stable.
To use `libcore`, add this flag to your crate root:
```rust,ignore
#![no_std]
```
This will remove the standard library, and bring the `core` crate into your
namespace for use:
```rust,ignore
#![no_std]
use core::cell::Cell;
```
You can find `libcore`'s documentation [here](https://doc.rust-lang.org/core/).

View File

@ -0,0 +1,18 @@
# MSVC toolchain support
![Minimum Rust version: 1.2](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg)
At the release of Rust 1.0, we only supported the GNU toolchain on Windows. With the
release of Rust 1.2, we introduced initial support for the MSVC toolchain. After that,
as support matured, we eventually made it the default choice for Windows users.
The difference between the two matters for interacting with C. If you're using a library
built with one toolchain or another, you need to match that with the appropriate Rust
toolchain. If you're not sure, go with MSVC; it's the default for good reason.
To use this feature, simply use Rust on Windows, and the installer will default to it.
If you'd prefer to switch to the GNU toolchain, you can install it with Rustup:
```console
$ rustup toolchain install stable-x86_64-pc-windows-gnu
```

View File

@ -0,0 +1,45 @@
# MUSL support for fully static binaries
![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg)
By default, Rust will statically link all Rust code. However, if you use the
standard library, it will dynamically link to the system's `libc`
implementation.
If you'd like a 100% static binary, the [`MUSL
libc`](https://www.musl-libc.org/) can be used on Linux.
## Installing MUSL support
To add support for MUSL, you need to choose the correct target. [The forge
has a full list of
targets](https://forge.rust-lang.org/platform-support.html) supported,
with a number of ones using `musl`.
If you're not sure what you want, it's probably `x86_64-unknown-linux-musl`,
for 64-bit Linux. We'll be using this target in this guide, but the
instructions remain the same for other targets, just change the name wherever
we mention the target.
To get support for this target, you use `rustup`:
```console
$ rustup target add x86_64-unknown-linux-musl
```
This will install support for the default toolchain; to install for other toolchains,
add the `--toolchain` flag. For example:
```console
$ rustup target add x86_64-unknown-linux-musl --toolchain=nightly
```
## Building with MUSL
To use this new target, pass the `--target` flag to Cargo:
```console
$ cargo build --target x86_64-unknown-linux-musl
```
The binary produced will now be built with MUSL!

View File

@ -0,0 +1,28 @@
# WebAssembly support
![Minimum Rust version: 1.14](https://img.shields.io/badge/Minimum%20Rust%20Version-1.14-brightgreen.svg) for `emscripten`
![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for `wasm32-unknown-unknown`
Rust has gained support for [WebAssembly](https://webassembly.org/), meaning
that you can run Rust code in your browser, client-side.
In Rust 1.14, we gained support through
[emscripten](http://kripken.github.io/emscripten-site/index.html). With it
installed, you can write Rust code and have it produce
[asm.js](http://asmjs.org/) (the precusor to wasm) and/or WebAssembly.
Here's an example of using this support:
```console
$ rustup target add wasm32-unknown-emscripten
$ echo 'fn main() { println!("Hello, Emscripten!"); }' > hello.rs
$ rustc --target=wasm32-unknown-emscripten hello.rs
$ node hello.js
```
However, in the meantime, Rust has also grown its own support, independent
from Emscripten. This is known as "the unknown target", because instead of
`wasm32-unknown-emscripten`, it's `wasm32-unknown-unknown`. This will be
the preferred target to use once it's ready, but for now, it's really
only well-supported in nightly.

View File

@ -0,0 +1,19 @@
# Documentation tests can now compile-fail
![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg)
You can now create `compile-fail` tests in Rustdoc, like this:
```
/// ```compile_fail
/// let x = 5;
/// x += 2; // shouldn't compile!
/// ```
# fn foo() {}
```
Please note that these kinds of tests can be more fragile than others, as
additions to Rust may cause code to compile when it previously would not.
Consider the first release with `?`, for example: code using `?` would fail
to compile on Rust 1.21, but compile successfully on Rust 1.22, causing your
test suite to start failing.

View File

@ -0,0 +1,6 @@
# `rustdoc`
[cf]: rust-2018/rustdoc/documentation-tests-can-now-compile-fail.html
In this chapter of the guide, we discuss a few improvements to `rustdoc`.
A notable addition to it was [that documentation tests can now compile-fail][cf].

View File

@ -0,0 +1,16 @@
# Rustdoc uses CommonMark
![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) for support by default
![Minimum Rust version: 1.23](https://img.shields.io/badge/Minimum%20Rust%20Version-1.23-red.svg) for support via a flag
Rustdoc lets you write documentation comments in Markdown. At Rust 1.0, we
were using the `hoedown` markdown implementation, written in C. Markdown is
more of a family of implementations of an idea, and so `hoedown` had its own
dialect, like many parsers. The [CommonMark project](https://commonmark.org/)
has attempted to define a more strict version of Markdown, and so now, Rustdoc
uses it by default.
As of Rust 1.23, we still defaulted to `hoedown`, but you could enable
Commonmark via a flag, `--enable-commonmark`. Today, we only support
CommonMark.

View File

@ -0,0 +1,212 @@
# Rustup for managing Rust versions
![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg) (this tool has its own versioning scheme and works with all Rust versions)
The [Rustup](https://rustup.rs/) tool has become *the* recommended way to
install Rust, and is advertised on our website. Its powers go further than
that though, allowing you to manage various versions, components, and
platforms.
## For installing Rust
To install Rust through Rustup, you can go to
<https://www.rust-lang.org/install.html>, which will let you know how to do
so on your platform. This will install both `rustup` itself and the `stable`
version of `rustc` and `cargo`.
To install a specific Rust version, you can use `rustup install`:
```console
$ rustup install 1.30.0
```
This works for a specific nightly, as well:
```console
$ rustup install nightly-2018-08-01
```
As well as any of our release channels:
```console
$ rustup install stable
$ rustup install beta
$ rustup install nightly
```
## For updating your installation
To update all of the various channels you may have installed:
```console
$ rustup update
```
This will look at everything you've installed, and if there are new releases,
will update anything that has one.
## Managing versions
To set the default toolchain to something other than `stable`:
```console
$ rustup toolchain default nightly
```
To use a toolchain other than the default, use `rustup run`:
```console
$ rustup run nightly cargo build
```
There's also an alias for this that's a little shorter:
```console
$ cargo +nightly build
```
If you'd like to have a different default per-directory, that's easy too!
If you run this inside of a project:
```console
$ rustup override set nightly
```
Then when you're in that directory, any invocations of `rustc` or `cargo`
will use that toolchain. To share this with others, you can create a
`rust-toolchain` file with the contents of a toolchain, and check it into
source control. Now, when someone clones your project, they'll get the
right version without needing to `override set` themselves.
## Installing other targets
Rust supports cross-compiling to other targets, and Rustup can help you
manage them. For example, to use MUSL:
```console
$ rustup target add x86_64-unknown-linux-musl
```
And then you can
```console
$ cargo build --target=x86_64-unknown-linux-musl
```
To see the full list of targets you can install:
```console
$ rustup target list
```
## Installing components
Components are used to install certain kinds of tools. While `cargo-install`
has you covered for most tools, some tools need deep integration into the
compiler. Rustup knows exactly what version of the compiler you're using, and
so it's got just the information that these tools need.
Components are per-toolchain, so if you want them to be available to more
than one toolchain, you'll need to install them multiple times. In the
following examples, add a `--toolchain` flag, set to the toolchain you
want to install for, `nightly` for example. Without this flag, it will
install the component for the default toolchain.
To see the full list of components you can install:
```console
$ rustup component list
```
Next, let's talk about some popular components and when you might want to
install them.
### `rust-docs`, for local documentation
This first component is installed by default when you install a toolchain. It
contains a copy of Rust's documentation, so that you can read it offline.
This component cannot be removed for now; if that's of interest, please
comment on [this
issue](https://github.com/rust-lang-nursery/rustup.rs/issues/998).
### `rust-src` for a copy of Rust's source code
The `rust-src` component can give you a local copy of Rust's source code. Why
might you need this? Well, autocompletion tools like Racer use this
information to know more about the functions you're trying to call.
```console
$ rustup component add rust-src
```
### The "preview" components
There are several components in a "preview" stage. These components currently
have `-preview` in their name, and this indicates that they're not quite 100%
ready for general consumption yet. Please try them out and give us feedback,
but know that they do not follow Rust's stability guarantees, and are still
actively changing, possibly in backwards-incompatible ways.
#### `rustfmt-preview` for automatic code formatting
![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg)
If you'd like to have your code automatically formatted, you can
install this component:
```console
$ rustup component add rustfmt-preview
```
This will install two tools, `rustfmt` and `cargo-fmt`, that will reformat your
code for you! For example:
```console
$ cargo fmt
```
will reformat your entire Cargo project.
#### `rls-preview` for IDE integration
![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg)
Many IDE features are built off of the [`langserver`
protocol](http://langserver.org/). To gain support for Rust with these IDEs,
you'll need to install the Rust language sever, aka the "RLS":
```console
$ rustup component add rls-preview
```
Your IDE should take it from there.
#### `clippy-preview` for more lints
For even more lints to help you write Rust code, you can install `clippy`:
```console
$ rustup component add clippy-preview
```
This will install `cargo-clippy` for you:
```console
$ cargo clippy
```
For more, check out [clippy's
documentation](https://github.com/rust-lang-nursery/rust-clippy).
#### `llvm-tools-preview` for using extra LLVM tools
If you'd like to use the `lld` linker, or other tools like `llvm-objdump` or
`llvm-objcopy`, you can install this component:
```console
$ rustup component add llvm-tools-preview
```
This is the newest component, and so doesn't have good documentation at the
moment.

View File

@ -0,0 +1,108 @@
# SIMD for faster computing
![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg)
The basics of [SIMD](https://en.wikipedia.org/wiki/SIMD) are now available!
SIMD stands for “single instruction, multiple data.” Consider a function like
this:
```rust
pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) {
for ((a, b), c) in a.iter().zip(b).zip(c) {
*c = *a + *b;
}
}
```
Here, were taking two slices, and adding the numbers together, placing the
result in a third slice. The simplest possible way to do this would be to do
exactly what the code does, and loop through each set of elements, add them
together, and store it in the result. However, compilers can often do better.
LLVM will usually “autovectorize” code like this, which is a fancy term for
“use SIMD.” Imagine that `a` and `b` were both 16 elements long. Each element
is a `u8`, and so that means that each slice would be 128 bits of data. Using
SIMD, we could put both `a` and `b` into 128 bit registers, add them together
in a *single* instruction, and then copy the resulting 128 bits into `c`.
Thatd be much faster!
While stable Rust has always been able to take advantage of
autovectorization, sometimes, the compiler just isnt smart enough to realize
that we can do something like this. Additionally, not every CPU has these
features, and so LLVM may not use them so your program can be used on a wide
variety of hardware. The `std::arch` module allows us to use these kinds of
instructions directly, which means we dont need to rely on a smart compiler.
Additionally, it includes some features that allow us to choose a particular
implementation based on various criteria. For example:
```rust,ignore
#[cfg(all(any(target_arch = "x86", target_arch = "x86_64"),
target_feature = "avx2"))]
fn foo() {
#[cfg(target_arch = "x86")]
use std::arch::x86::_mm256_add_epi64;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::_mm256_add_epi64;
unsafe {
_mm256_add_epi64(...);
}
}
```
Here, we use cfg flags to choose the correct version based on the machine
were targeting; on x86 we use that version, and on x86_64 we use its
version. We can also choose at runtime:
```rust,ignore
fn foo() {
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
{
if is_x86_feature_detected!("avx2") {
return unsafe { foo_avx2() };
}
}
foo_fallback();
}
```
Here, we have two versions of the function: one which uses AVX2, a specific
kind of SIMD feature that lets you do 256-bit operations. The
`is_x86_feature_detected!` macro will generate code that detects if your CPU
supports AVX2, and if so, calls the foo_avx2 function. If not, then we fall
back to a non-AVX implementation, foo_fallback. This means that our code will
run super fast on CPUs that support AVX2, but still work on ones that dont,
albeit slower.
If all of this seems a bit low-level and fiddly, well, it is! `std::arch` is
specifically primitives for building these kinds of things. We hope to
eventually stabilize a `std::simd` module with higher-level stuff in the
future. But landing the basics now lets the ecosystem experiment with higher
level libraries starting today. For example, check out the
[faster](https://github.com/AdamNiederer/faster) crate. Heres a code snippet
with no SIMD:
```rust,ignore
let lots_of_3s = (&[-123.456f32; 128][..]).iter()
.map(|v| {
9.0 * v.abs().sqrt().sqrt().recip().ceil().sqrt() - 4.0 - 2.0
})
.collect::<Vec<f32>>();
```
To use SIMD with this code via faster, youd change it to this:
```rust,ignore
let lots_of_3s = (&[-123.456f32; 128][..]).simd_iter()
.simd_map(f32s(0.0), |v| {
f32s(9.0) * v.abs().sqrt().rsqrt().ceil().sqrt() - f32s(4.0) - f32s(2.0)
})
.scalar_collect();
```
It looks almost the same: `simd_iter` instead of `iter`, `simd_map` instead of `map`,
`f32s(2.0)` instead of `2.0`. But you get a SIMD-ified version generated for you.
Beyond that, you may never write any of this yourself, but as always, the
libraries you depend on may. For example, the regex crate contains these SIMD
speedups without you needing to do anything at all!

View File

@ -0,0 +1,91 @@
# Slice patterns
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
Have you ever tried to pattern match on the contents and structure of a slice?
Rust 2018 will let you do just that.
For example, say we want to accept a list of names and respond to that with a
greeting. With slice patterns, we can do that easy as pie with:
```rust
fn main() {
greet(&[]);
// output: Bummer, there's no one here :(
greet(&["Alan"]);
// output: Hey, there Alan! You seem to be alone.
greet(&["Joan", "Hugh"]);
// output: Hello, Joan and Hugh. Nice to see you are at least 2!
greet(&["John", "Peter", "Stewart"]);
// output: Hey everyone, we seem to be 3 here today.
}
fn greet(people: &[&str]) {
match people {
[] => println!("Bummer, there's no one here :("),
[only_one] => println!("Hey, there {}! You seem to be alone.", only_one),
[first, second] => println!(
"Hello, {} and {}. Nice to see you are at least 2!",
first, second
),
_ => println!("Hey everyone, we seem to be {} here today.", people.len()),
}
}
```
Now, you don't have to check the length first.
We can also match on arrays like so:
```rust
let arr = [1, 2, 3];
assert_eq!("ends with 3", match arr {
[_, _, 3] => "ends with 3",
[a, b, c] => "ends with something else",
});
```
## More details
### Exhaustive patterns
In the first example, note in particular the `_ => ...` pattern.
Since we are matching on a slice, it could be of any length, so we need a
*"catch all pattern"* to handle it. If we forgot the `_ => ...` or
`identifier => ...` pattern, we would instead get an error saying:
```ignore
error[E0004]: non-exhaustive patterns: `&[_, _, _]` not covered
```
If we added a case for a slice of size `3` we would instead get:
```ignore
error[E0004]: non-exhaustive patterns: `&[_, _, _, _]` not covered
```
and so on...
### Arrays and exact lengths
In the second example above, since arrays in Rust are of known lengths,
we have to match on exactly three elements.
If we try to match on 2 or 4 elements,we get the errors:
```ignore
error[E0527]: pattern requires 2 elements but array has 3
```
and
```ignore
error[E0527]: pattern requires 4 elements but array has 3
```
### In the pipeline
[the tracking issue]: https://github.com/rust-lang/rust/issues/23121
When it comes to slice patterns, more advanced forms are planned but
have not been stabilized yet. To learn more, follow [the tracking issue].

View File

@ -0,0 +1,35 @@
# An attribute for deprecation
![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg)
If you're writing a library, and you'd like to deprecate something, you can
use the `deprecated` attribute:
```rust
#[deprecated(
since = "0.2.1",
note = "Please use the bar function instead"
)]
pub fn foo() {
// ...
}
```
This will give your users a warning if they use the deprecated functionality:
```text
Compiling playground v0.0.1 (file:///playground)
warning: use of deprecated item 'foo': Please use the bar function instead
--> src/main.rs:10:5
|
10 | foo();
| ^^^
|
= note: #[warn(deprecated)] on by default
```
Both `since` and `note` are optional.
`since` can be in the future; you can put whatever you'd like, and what's put in
there isn't checked.

View File

@ -0,0 +1,49 @@
# Improved error messages
![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg)
We're always working on error improvements, and there are little improvements
in almost every Rust version, but in Rust 1.12, a significant overhaul of the
error message system was created.
For example, here's some code that produces an error:
```rust,ignore
fn main() {
let mut x = 5;
let y = &x;
x += 1;
}
```
Here's the error in Rust 1.11:
```text
foo.rs:6:5: 6:11 error: cannot assign to `x` because it is borrowed [E0506]
foo.rs:6 x += 1;
^~~~~~
foo.rs:4:14: 4:15 note: borrow of `x` occurs here
foo.rs:4 let y = &x;
^
foo.rs:6:5: 6:11 help: run `rustc --explain E0506` to see a detailed explanation
```
Here's the error in Rust 1.28:
```text
error[E0506]: cannot assign to `x` because it is borrowed
--> foo.rs:6:5
|
4 | let y = &x;
| - borrow of `x` occurs here
5 |
6 | x += 1;
| ^^^^^^ assignment to borrowed `x` occurs here
error: aborting due to previous error
```
This error isn't terribly different, but shows off how the format has changed. It shows
off your code in context, rather than just showing the text of the lines themselves.

View File

@ -0,0 +1,23 @@
# Incremental Compilation
![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg)
Back in September of 2016, we [blogged about Incremental
Compilation](https://blog.rust-lang.org/2016/09/08/incremental.html). While
that post goes into the details, the idea is basically this: when youre
working on a project, you often compile it, then change something small, then
compile again. Historically, the compiler has compiled your entire project,
no matter how little youve changed the code. The idea with incremental
compilation is that you only need to compile the code youve actually
changed, which means that that second build is faster.
This is now turned on by default. This means that your builds should be
faster! Dont forget about cargo check when trying to get the lowest possible
build times.
This is still not the end story for compiler performance generally, nor
incremental compilation specifically. We have a lot more work planned in the
future.
One small note about this change: it makes builds faster, but makes the final
binary a bit slower. For this reason, it's not turned on in release builds.

View File

@ -0,0 +1,6 @@
# The compiler
[errors]: rust-2018/the-compiler/improved-error-messages.html
In this chapter of the guide, we discuss a few improvements to the compiler.
A notable addition here is our new and [improved error messages][errors].

View File

@ -0,0 +1,117 @@
# Associated constants
![Minimum Rust version: 1.20](https://img.shields.io/badge/Minimum%20Rust%20Version-1.20-brightgreen.svg)
You can define traits, structs, and enums that have “associated functions”:
```rust
struct Struct;
impl Struct {
fn foo() {
println!("foo is an associated function of Struct");
}
}
fn main() {
Struct::foo();
}
```
These are called “associated functions” because they are functions that are
associated with the type, that is, theyre attached to the type itself, and
not any particular instance.
Rust 1.20 adds the ability to define “associated constants” as well:
```rust
struct Struct;
impl Struct {
const ID: u32 = 0;
}
fn main() {
println!("the ID of Struct is: {}", Struct::ID);
}
```
That is, the constant `ID` is associated with `Struct`. Like functions,
associated constants work with traits and enums as well.
Traits have an extra ability with associated constants that gives them some
extra power. With a trait, you can use an associated constant in the same way
youd use an associated type: by declaring it, but not giving it a value. The
implementor of the trait then declares its value upon implementation:
```rust
trait Trait {
const ID: u32;
}
struct Struct;
impl Trait for Struct {
const ID: u32 = 5;
}
fn main() {
println!("{}", Struct::ID);
}
```
Before this feature, if you wanted to make a trait that represented floating
point numbers, youd have to write this:
```rust
trait Float {
fn nan() -> Self;
fn infinity() -> Self;
// ...
}
```
This is slightly unwieldy, but more importantly, because theyre functions,
they cannot be used in constant expressions, even though they only return a
constant. Because of this, a design for `Float` would also have to include
constants as well:
```rust,ignore
mod f32 {
const NAN: f32 = 0.0f32 / 0.0f32;
const INFINITY: f32 = 1.0f32 / 0.0f32;
impl Float for f32 {
fn nan() -> Self {
f32::NAN
}
fn infinity() -> Self {
f32::INFINITY
}
}
}
```
Associated constants let you do this in a much cleaner way. This trait
definition:
```rust
trait Float {
const NAN: Self;
const INFINITY: Self;
// ...
}
```
Leads to this implementation:
```rust,ignore
mod f32 {
impl Float for f32 {
const NAN: f32 = 0.0f32 / 0.0f32;
const INFINITY: f32 = 1.0f32 / 0.0f32;
}
}
```
much cleaner, and more versatile.

View File

@ -0,0 +1,42 @@
# `dyn Trait` for trait objects
![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg)
The `dyn Trait` feature is the new syntax for using trait objects. In short:
* `Box<Trait>` becomes `Box<dyn Trait>`
* `&Trait` and `&mut Trait` become `&dyn Trait` and `&mut dyn Trait`
And so on. In code:
```rust
trait Trait {}
impl Trait for i32 {}
// old
fn function1() -> Box<Trait> {
# unimplemented!()
}
// new
fn function2() -> Box<dyn Trait> {
# unimplemented!()
}
```
That's it!
## More details
Using just the trait name for trait objects turned out to be a bad decision.
The current syntax is often ambiguous and confusing, even to veterans,
and favors a feature that is not more frequently used than its alternatives,
is sometimes slower, and often cannot be used at all when its alternatives can.
Furthermore, with `impl Trait` arriving, "`impl Trait` vs `dyn Trait`" is much
more symmetric, and therefore a bit nicer, than "`impl Trait` vs `Trait`".
`impl Trait` is explained [here](rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.html)
In the new edition, you should therefore prefer `dyn Trait` to just `Trait`
where you need a trait object.

View File

@ -0,0 +1,168 @@
# `impl Trait` for returning complex types with ease
![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg)
`impl Trait` is the new way to specify unnamed but concrete types that
implement a specific trait. There are two places you can put it: argument
position, and return position.
```rust,ignore
trait Trait {}
// argument position
fn foo(arg: impl Trait) {
}
// return position
fn foo() -> impl Trait {
}
```
## Argument Position
In argument position, this feature is quite simple. These two forms are
almost the same:
```rust,ignore
trait Trait {}
fn foo<T: Trait>(arg: T) {
}
fn foo(arg: impl Trait) {
}
```
That is, it's a slightly shorter syntax for a generic type parameter. It
means, "`arg` is an argument that takes any type that implements the `Trait`
trait."
However, there's also an important technical difference between `T: Trait`
and `impl Trait` here. When you write the former, you can specify the type of
`T` at the call site with turbo-fish syntax as with `foo::<usize>(1)`. In the
case of `impl Trait`, if it is used anywhere in the function definition, then
you can't use turbo-fish at all. Therefore, you should be mindful that
changing both from and to `impl Trait` can constitute a breaking change for
the users of your code.
## Return Position
In return position, this feature is more interesting. It means "I am
returning some type that implements the `Trait` trait, but I'm not going to
tell you exactly what the type is." Before `impl Trait`, you could do this
with trait objects:
```rust
trait Trait {}
impl Trait for i32 {}
fn returns_a_trait_object() -> Box<dyn Trait> {
Box::new(5)
}
```
However, this has some overhead: the `Box<T>` means that there's a heap
allocation here, and this will use dynamic dispatch. See the `dyn Trait`
section for an explanation of this syntax. But we only ever return one
possible thing here, the `Box<i32>`. This means that we're paying for dynamic
dispatch, even though we don't use it!
With `impl Trait`, the code above could be written like this:
```rust
trait Trait {}
impl Trait for i32 {}
fn returns_a_trait_object() -> impl Trait {
5
}
```
Here, we have no `Box<T>`, no trait object, and no dynamic dispatch. But we
still can obscure the `i32` return type.
With `i32`, this isn't super useful. But there's one major place in Rust
where this is much more useful: closures.
### `impl Trait` and closures
> If you need to catch up on closures, check out [their chapter in the
> book](https://doc.rust-lang.org/book/second-edition/ch13-01-closures.html).
In Rust, closures have a unique, un-writable type. They do implement the `Fn`
family of traits, however. This means that previously, the only way to return
a closure from a function was to use a trait object:
```rust
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
```
You couldn't write the type of the closure, only use the `Fn` trait. That means
that the trait object is necessary. However, with `impl Trait`:
```rust
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
```
We can now return closures by value, just like any other type!
## More details
The above is all you need to know to get going with `impl Trait`, but for
some more nitty-gritty details: type parameters and `impl Trait` work
slightly differently when they're in argument position versus return
position. Consider this function:
```rust,ignore
fn foo<T: Trait>(x: T) {
```
When you call it, you set the type, `T`. "you" being the caller here. This
signature says "I accept any type that implements Trait." ("any type" ==
universal in the jargon)
This version:
```rust,ignore
fn foo<T: Trait>() -> T {
```
is similar, but also different. You, the caller, provide the type you want,
`T`, and then the function returns it. You can see this in Rust today with
things like parse or collect:
```rust,ignore
let x: i32 = "5".parse()?;
let x: u64 = "5".parse()?;
```
Here, `.parse` has this signature:
```rust,ignore
pub fn parse<F>(&self) -> Result<F, <F as FromStr>::Err> where
F: FromStr,
```
Same general idea, though with a result type and `FromStr` has an associated
type... anyway, you can see how `F` is in the return position here. So you
have the ability to choose.
With `impl Trait`, you're saying "hey, some type exists that implements this
trait, but I'm not gonna tell you what it is.". So now, the caller can't
choose, and the function itself gets to choose. If we tried to define parse
with `Result<impl F,...` as the return type, it wouldn't work.
### Using `impl Trait` in more places
As previously mentioned, as a start, you will only be able to use `impl Trait`
as the argument or return type of a free or inherent function. However,
`impl Trait` can't be used inside implementations of traits, nor can it be
used as the type of a let binding or inside a type alias. Some of these
restrictions will eventually be lifted. For more information, see the
[tracking issue on `impl Trait`](https://github.com/rust-lang/rust/issues/34511).

View File

@ -0,0 +1,6 @@
# Trait system
[impl_trait]: rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.html
In this chapter of the guide, we discuss a few improvements to the trait system.
The most notable of these is [`impl Trait`][impl_trait].

View File

@ -0,0 +1,28 @@
# More container types support trait objects
![Minimum Rust version: 1.2](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg)
In Rust 1.0, only certain, special types could be used to create [trait
objects](https://doc.rust-lang.org/book/second-edition/ch17-02-trait-objects.html).
With Rust 1.2, that restriction was lifted, and more types became able to do this. For example,
`Rc<T>`, one of Rust's reference-counted types:
```rust
use std::rc::Rc;
trait Foo {}
impl Foo for i32 {
}
fn main() {
let obj: Rc<dyn Foo> = Rc::new(5);
}
```
This code would not work with Rust 1.0, but now works.
> If you haven't seen the `dyn` syntax before, see the section on it. For
> versions that do not support it, replace `Rc<dyn Foo>` with `Rc<Foo>`.

View File

@ -0,0 +1,23 @@
# No more anonymous trait parameters
![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg)
In accordance with RFC [#1685](https://github.com/rust-lang/rfcs/pull/1685),
parameters in trait method declarations are no longer allowed to be anonymous.
For example, in the 2015 edition, this was allowed:
```rust
trait Foo {
fn foo(&self, u8);
}
```
In the 2018 edition, all parameters must be given an argument name (even if it's just
`_`):
```rust
trait Foo {
fn foo(&self, baz: u8);
}
```

View File

@ -2,20 +2,20 @@
#### The Dark Arts of Advanced and Unsafe Rust Programming
# NOTE: This is a draft document that discusses several unstable aspects of Rust, and may contain serious errors or outdated information.
> Instead of the programs I had hoped for, there came only a shuddering blackness
and ineffable loneliness; and I saw at last a fearful truth which no one had
ever dared to breathe before — the unwhisperable secret of secrets — The fact
that this language of stone and stridor is not a sentient perpetuation of Rust
as London is of Old London and Paris of Old Paris, but that it is in fact
quite unsafe, its sprawling body imperfectly embalmed and infested with queer
quite `unsafe`, its sprawling body imperfectly embalmed and infested with queer
animate things which have nothing to do with it as it was in compilation.
This book digs into all the awful details that are necessary to understand in
order to write correct Unsafe Rust programs. Due to the nature of this problem,
it may lead to unleashing untold horrors that shatter your psyche into a billion
infinitesimal fragments of despair.
This book digs into all the awful details that you need to understand when
writing Unsafe Rust programs.
> THE KNOWLEDGE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF UNLEASHING INDESCRIBABLE HORRORS THAT
SHATTER YOUR PSYCHE AND SET YOUR MIND ADRIFT IN THE UNKNOWABLY INFINITE COSMOS.
Should you wish a long and happy career of writing Rust programs, you should
turn back now and forget you ever saw this book. It is not necessary. However

View File

@ -3,3 +3,17 @@
Low-level programming cares a lot about data layout. It's a big deal. It also
pervasively influences the rest of the language, so we're going to start by
digging into how data is represented in Rust.
This chapter is ideally in agreement with, and rendered redundant by,
the [Type Layout section of the Reference][ref-type-layout]. When this
book was first written, the reference was in complete disrepair, and the
Rustonomicon was attempting to serve as a partial replacement for the reference.
This is no longer the case, so this whole chapter can ideally be deleted.
We'll keep this chapter around for a bit longer, but ideally you should be
contributing any new facts or improvements to the Reference instead.
ref-type-layout: ../reference/type-layout.html

View File

@ -12,7 +12,7 @@ Note that this is not a problem that all assignments need worry about. In
particular, assigning through a dereference unconditionally drops, and assigning
in a `let` unconditionally doesn't drop:
```
```rust
let mut x = Box::new(0); // let makes a fresh variable, so never need to drop
let y = &mut x;
*y = Box::new(1); // Deref assumes the referent is initialized, so always drops

View File

@ -1,7 +1,7 @@
# Exotically Sized Types
Most of the time, we think in terms of types with a fixed, positive size. This
is not always the case, however.
Most of the time, we expect types to have a statically known and positive size.
This isn't always the case in Rust.
@ -9,47 +9,80 @@ is not always the case, however.
# Dynamically Sized Types (DSTs)
Rust in fact supports Dynamically Sized Types (DSTs): types without a statically
Rust supports Dynamically Sized Types (DSTs): types without a statically
known size or alignment. On the surface, this is a bit nonsensical: Rust *must*
know the size and alignment of something in order to correctly work with it! In
this regard, DSTs are not normal types. Due to their lack of a statically known
size, these types can only exist behind some kind of pointer. Any pointer to a
DST consequently becomes a *fat* pointer consisting of the pointer and the
this regard, DSTs are not normal types. Because they lack a statically known
size, these types can only exist behind a pointer. Any pointer to a
DST consequently becomes a *wide* pointer consisting of the pointer and the
information that "completes" them (more on this below).
There are two major DSTs exposed by the language: trait objects, and slices.
There are two major DSTs exposed by the language:
* trait objects: `dyn MyTrait`
* slices: `[T]`, `str`, and others
A trait object represents some type that implements the traits it specifies.
The exact original type is *erased* in favor of runtime reflection
with a vtable containing all the information necessary to use the type.
This is the information that completes a trait object: a pointer to its vtable.
The information that completes a trait object pointer is the vtable pointer.
The runtime size of the pointee can be dynamically requested from the vtable.
A slice is simply a view into some contiguous storage -- typically an array or
`Vec`. The information that completes a slice is just the number of elements
it points to.
`Vec`. The information that completes a slice pointer is just the number of elements
it points to. The runtime size of the pointee is just the statically known size
of an element multiplied by the number of elements.
Structs can actually store a single DST directly as their last field, but this
makes them a DST as well:
```rust
// Can't be stored on the stack directly
struct Foo {
struct MySuperSlice {
info: u32,
data: [u8],
}
```
Although such a type is largely useless without a way to construct it. Currently the
only properly supported way to create a custom DST is by making your type generic
and performing an *unsizing coercion*:
```rust
struct MySuperSliceable<T: ?Sized> {
info: u32,
data: T
}
fn main() {
let sized: MySuperSliceable<[u8; 8]> = MySuperSliceable {
info: 17,
data: [0; 8],
};
let dynamic: &MySuperSliceable<[u8]> = &sized;
// prints: "17 [0, 0, 0, 0, 0, 0, 0, 0]"
println!("{} {:?}", dynamic.info, &dynamic.data);
}
```
(Yes, custom DSTs are a largely half-baked feature for now.)
# Zero Sized Types (ZSTs)
Rust actually allows types to be specified that occupy no space:
Rust also allows types to be specified that occupy no space:
```rust
struct Foo; // No fields = no size
struct Nothing; // No fields = no size
// All fields have no size = no size
struct Baz {
foo: Foo,
struct LotsOfNothing {
foo: Nothing,
qux: (), // empty tuple has no size
baz: [u8; 0], // empty array has no size
}
@ -57,13 +90,13 @@ struct Baz {
On their own, Zero Sized Types (ZSTs) are, for obvious reasons, pretty useless.
However as with many curious layout choices in Rust, their potential is realized
in a generic context: Rust largely understands that any operation that produces
or stores a ZST can be reduced to a no-op. First off, storing it doesn't even
make sense -- it doesn't occupy any space. Also there's only one value of that
type, so anything that loads it can just produce it from the aether -- which is
in a generic context: Rust largely understands that any operation that produces
or stores a ZST can be reduced to a no-op. First off, storing it doesn't even
make sense -- it doesn't occupy any space. Also there's only one value of that
type, so anything that loads it can just produce it from the aether -- which is
also a no-op since it doesn't occupy any space.
One of the most extreme example's of this is Sets and Maps. Given a
One of the most extreme examples of this is Sets and Maps. Given a
`Map<Key, Value>`, it is common to implement a `Set<Key>` as just a thin wrapper
around `Map<Key, UselessJunk>`. In many languages, this would necessitate
allocating space for UselessJunk and doing work to store and load UselessJunk
@ -78,9 +111,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)
may return `nullptr` when a zero-sized allocation is requested, which is
indistinguishable from out of memory.
and standard allocators may return `null` when a zero-sized allocation is
requested, which is indistinguishable from the out of memory result.
@ -97,7 +129,7 @@ enum Void {} // No variants = EMPTY
```
Empty types are even more marginal than ZSTs. The primary motivating example for
Void types is type-level unreachability. For instance, suppose an API needs to
an empty type is type-level unreachability. For instance, suppose an API needs to
return a Result in general, but a specific case actually is infallible. It's
actually possible to communicate this at the type level by returning a
`Result<T, Void>`. Consumers of the API can confidently unwrap such a Result
@ -125,9 +157,35 @@ But this trick doesn't work yet.
One final subtle detail about empty types is that raw pointers to them are
actually valid to construct, but dereferencing them is Undefined Behavior
because that doesn't actually make sense. That is, you could model C's `void *`
type with `*const Void`, but this doesn't necessarily gain anything over using
e.g. `*const ()`, which *is* safe to randomly dereference.
because that wouldn't make sense.
We recommend against modelling C's `void*` type with `*const Void`.
A lot of people started doing that but quickly ran into trouble because
Rust doesn't really have any safety guards against trying to instantiate
empty types with unsafe code, and if you do it, it's Undefined Behaviour.
This was especially problematic because developers had a habit of converting
raw pointers to references and `&Void` is *also* Undefined Behaviour to
construct.
`*const ()` (or equivalent) works reasonably well for `void*`, and can be made
into a reference without any safety problems. It still doesn't prevent you from
trying to read or write values, but at least it compiles to a no-op instead
of UB.
# Extern Types
There is [an accepted RFC][extern-types] to add proper types with an unknown size,
called *extern types*, which would let Rust developers model things like C's `void*`
and other "declared but never defined" types more accurately. However as of
Rust 2018, the feature is stuck in limbo over how `size_of::<MyExternType>()`
should behave.
[dst-issue]: https://github.com/rust-lang/rust/issues/26403
[extern-types]: https://github.com/rust-lang/rfcs/blob/master/text/1861-extern-types.md

View File

@ -15,18 +15,26 @@ or C++. Any type you expect to pass through an FFI boundary should have
necessary to soundly do more elaborate tricks with data layout such as
reinterpreting values as a different type.
However, the interaction with Rust's more exotic data layout features must be
We strongly recommend using [rust-bindgen][] and/or [cbdingen][] to manage your FFI
boundaries for you. The Rust team works closely with those projects to ensure
that they work robustly and are compatible with current and future guarantees
about type layouts and reprs.
The interaction of `repr(C)` with Rust's more exotic data layout features must be
kept in mind. Due to its dual purpose as "for FFI" and "for layout control",
`repr(C)` can be applied to types that will be nonsensical or problematic if
passed through the FFI boundary.
* ZSTs are still zero-sized, even though this is not a standard behavior in
C, and is explicitly contrary to the behavior of an empty type in C++, which
still consumes a byte of space.
says they should still consume a byte of space.
* DST pointers (fat pointers), tuples, and enums with fields are not a concept
* DST pointers (wide pointers) and tuples are not a concept
in C, and as such are never FFI-safe.
* Enums with fields also aren't a concept in C or C++, but a valid bridging
of the types [is defined][really-tagged].
* If `T` is an [FFI-safe non-nullable pointer
type](ffi.html#the-nullable-pointer-optimization),
`Option<T>` is guaranteed to have the same layout and ABI as `T` and is
@ -36,13 +44,13 @@ still consumes a byte of space.
* Tuple structs are like structs with regards to `repr(C)`, as the only
difference from a struct is that the fields arent named.
* 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 application
binary interface (ABI). Note that enum representation in C is implementation
* `repr(C)` is equivalent to one of `repr(u*)` (see the next section) for
fieldless enums. The chosen size is the default enum size for the target platform's C
application binary interface (ABI). Note that enum representation in C is implementation
defined, so this is really a "best guess". In particular, this may be incorrect
when the C code of interest is compiled with certain flags.
* Field-less enums with `repr(C)` or `repr(u*)` still may not be set to an
* Fieldless enums with `repr(C)` or `repr(u*)` still may not be set to an
integer value without a corresponding variant, even though this is
permitted behavior in C or C++. It is undefined behavior to (unsafely)
construct an instance of an enum that does not match one of its
@ -58,12 +66,12 @@ be additional zero-sized fields). The effect is that the layout and ABI of the
whole struct is guaranteed to be the same as that one field.
The goal is to make it possible to transmute between the single field and the
struct. An example of that is the [`UnsafeCell`], which can be transmuted into
struct. An example of that is [`UnsafeCell`], which can be transmuted into
the type it wraps.
Also, passing the struct through FFI where the inner field type is expected on
the other side is allowed. In particular, this is necessary for `struct
Foo(f32)` to have the same ABI as `f32`.
the other side is guaranteed to work. In particular, this is necessary for `struct
Foo(f32)` to always have the same ABI as `f32`.
More details are in the [RFC][rfc-transparent].
@ -71,20 +79,22 @@ More details are in the [RFC][rfc-transparent].
# repr(u*), repr(i*)
These specify the size to make a field-less enum. If the discriminant overflows
These specify the size to make a fieldless enum. If the discriminant overflows
the integer it has to fit in, it will produce a compile-time error. You can
manually ask Rust to allow this by setting the overflowing element to explicitly
be 0. However Rust will not allow you to create an enum where two variants have
the same discriminant.
The term "field-less enum" only means that the enum doesn't have data in any
of its variants. A field-less enum without a `repr(u*)` or `repr(C)` is
The term "fieldless enum" only means that the enum doesn't have data in any
of its variants. A fieldless enum without a `repr(u*)` or `repr(C)` is
still a Rust native type, and does not have a stable ABI representation.
Adding a `repr` causes it to be treated exactly like the specified
integer size for ABI purposes.
Any enum with fields is a Rust type with no guaranteed ABI (even if the
only data is `PhantomData` or something else with zero size).
If the enum has fields, the effect is similar to the effect of `repr(C)`
in that there is a defined layout of the type. This makes it possible to
pass the enum to C code, or access the type's raw representation and directly
manipulate its tag and fields. See [the RFC][really-tagged] for details.
Adding an explicit `repr` to an enum suppresses the null-pointer
optimization.
@ -107,13 +117,16 @@ compiler might be able to paper over alignment issues with shifts and masks.
However if you take a reference to a packed field, it's unlikely that the
compiler will be able to emit code to avoid an unaligned load.
**[As of Rust 1.30.0 this still can cause undefined behavior.][ub loads]**
**[As of Rust 2018, this still can cause undefined behavior.][ub loads]**
`repr(packed)` is not to be used lightly. Unless you have extreme requirements,
this should not be used.
This repr is a modifier on `repr(C)` and `repr(rust)`.
# repr(align(n))
`repr(align(n))` (where `n` is a power of two) forces the type to have an
@ -126,8 +139,15 @@ kinds of concurrent code).
This is a modifier on `repr(C)` and `repr(rust)`. It is incompatible with
`repr(packed)`.
[reference]: https://github.com/rust-rfcs/unsafe-code-guidelines/tree/master/reference/src/representation
[drop flags]: drop-flags.html
[ub loads]: https://github.com/rust-lang/rust/issues/27060
[`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html
[rfc-transparent]: https://github.com/rust-lang/rfcs/blob/master/text/1758-repr-transparent.md
[really-tagged]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
[rust-bindgen]: https://rust-lang-nursery.github.io/rust-bindgen/
[cbindgen]: https://github.com/eqrion/cbindgen

View File

@ -27,7 +27,7 @@ useful such as the information needed by drop check.
Iter logically contains a bunch of `&'a T`s, so this is exactly what we tell
the PhantomData to simulate:
```
```rust
use std::marker;
struct Iter<'a, T: 'a> {
@ -42,7 +42,7 @@ over `'a` and `T`. Everything Just Works.
Another important example is Vec, which is (approximately) defined as follows:
```
```rust
struct Vec<T> {
data: *const T, // *const for variance!
len: usize,
@ -66,7 +66,7 @@ In order to tell dropck that we *do* own values of type T, and therefore may
drop some T's when *we* drop, we must add an extra PhantomData saying exactly
that:
```
```rust
use std::marker;
struct Vec<T> {

View File

@ -2,12 +2,14 @@
First and foremost, all types have an alignment specified in bytes. The
alignment of a type specifies what addresses are valid to store the value at. A
value of alignment `n` must only be stored at an address that is a multiple of
value with alignment `n` must only be stored at an address that is a multiple of
`n`. So alignment 2 means you must be stored at an even address, and 1 means
that you can be stored anywhere. Alignment is at least 1, and always a power
of 2. Most primitives are generally aligned to their size, although this is
platform-specific behavior. In particular, on x86 `u64` and `f64` may be only
aligned to 32 bits.
of 2.
Primitives are usually aligned to their size, although this is
platform-specific behavior. For example, on x86 `u64` and `f64` are often
aligned to 4 bytes (32 bits).
A type's size must always be a multiple of its alignment. This ensures that an
array of that type may always be indexed by offsetting by a multiple of its
@ -20,12 +22,12 @@ Rust gives you the following ways to lay out composite data:
* tuples (anonymous product types)
* arrays (homogeneous product types)
* enums (named sum types -- tagged unions)
* unions (untagged)
* unions (untagged unions)
An enum is said to be *field-less* if none of its variants have associated data.
Composite structures will have an alignment equal to the maximum
of their fields' alignment. Rust will consequently insert padding where
By default, composite structures have an alignment equal to the maximum
of their fields' alignments. Rust will consequently insert padding where
necessary to ensure that all fields are properly aligned and that the overall
type's size is a multiple of its alignment. For instance:
@ -37,7 +39,7 @@ struct A {
}
```
will be 32-bit aligned on an architecture that aligns these primitives to their
will be 32-bit aligned on a target that aligns these primitives to their
respective sizes. The whole struct will therefore have a size that is a multiple
of 32-bits. It may become:
@ -64,8 +66,8 @@ struct A {
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:
densely packed and in-order), the layout of data is not specified by default.
Given the two following struct definitions:
```rust
struct A {
@ -81,8 +83,7 @@ struct B {
Rust *does* guarantee that two instances of A have their data laid out in
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.
instance of A has the same field ordering or padding as an instance of B.
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
@ -119,7 +120,7 @@ struct Foo<u32, u16> {
}
```
The latter case quite simply wastes space. An optimal use of space therefore
The latter case quite simply wastes space. An optimal use of space
requires different monomorphizations to have *different field orderings*.
Enums make this consideration even more complicated. Naively, an enum such as:
@ -132,7 +133,7 @@ enum Foo {
}
```
would be laid out as:
might be laid out as:
```rust
struct FooRepr {
@ -141,23 +142,22 @@ struct FooRepr {
}
```
And indeed this is approximately how it would be laid out in general (modulo the
And indeed this is approximately how it would be laid out (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": 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>()`.
nullable pointer variant (e.g. `Some(&T)`) makes the tag unnecessary. A null
pointer can safely be interpreted as the unit (`None`) variant. 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 could
use fairly elaborate algorithms to cache bits throughout nested types with
special constrained representations. As such it is *especially* desirable that
use fairly elaborate algorithms to store bits throughout nested types with
forbidden values. As such it is *especially* desirable that
we leave enum layout unspecified today.
[dst]: exotic-sizes.html#dynamically-sized-types-dsts

View File

@ -3,53 +3,135 @@
Subtyping is a relationship between types that allows statically typed
languages to be a bit more flexible and permissive.
The most common and easy to understand example of this can be found in
languages with inheritance. Consider an Animal type which has an `eat()`
method, and a Cat type which extends Animal, adding a `meow()` method.
Without subtyping, if someone were to write a `feed(Animal)` function, they
wouldn't be able to pass a Cat to this function, because a Cat isn't *exactly*
an Animal. But being able to pass a Cat where an Animal is expected seems
fairly reasonable. After all, a Cat is just an Animal *and more*. Something
having extra features that can be ignored shouldn't be any impediment to
using it!
Subtyping in Rust is a bit different from subtyping in other languages. This
makes it harder to give simple examples, which is a problem since subtyping,
and especially variance, are already hard to understand properly. As in,
even compiler writers mess it up all the time.
This is exactly what subtyping lets us do. Because a Cat is an Animal *and more*
we say that Cat is a *subtype* of Animal. We then say that anywhere a value of
a certain type is expected, a value with a subtype can also be supplied. Ok
actually it's a lot more complicated and subtle than that, but that's the
basic intuition that gets you by in 99% of the cases. We'll cover why it's
*only* 99% later in this section.
To keep things simple, this section will consider a small extension to the
Rust language that adds a new and simpler subtyping relationship. After
establishing concepts and issues under this simpler system,
we will then relate it back to how subtyping actually occurs in Rust.
Although Rust doesn't have any notion of structural inheritance, it *does*
include subtyping. In Rust, subtyping derives entirely from lifetimes. Since
lifetimes are regions of code, we can partially order them based on the
*contains* (outlives) relationship.
So here's our simple extension, *Objective Rust*, featuring three new types:
Subtyping on lifetimes is in terms of that relationship: if `'big: 'small`
("big contains small" or "big outlives small"), then `'big` is a subtype
```rust
trait Animal {
fn snuggle(&self);
fn eat(&mut self);
}
trait Cat: Animal {
fn meow(&self);
}
trait Dog: Animal {
fn bark(&self);
}
```
But unlike normal traits, we can use them as concrete and sized types, just like structs.
Now, say we have a very simple function that takes an Animal, like this:
```rust,ignore
fn love(pet: Animal) {
pet.snuggle();
}
```
By default, static types must match *exactly* for a program to compile. As such,
this code won't compile:
```rust,ignore
let mr_snuggles: Cat = ...;
love(mr_snuggles); // ERROR: expected Animal, found Cat
```
Mr. Snuggles is a Cat, and Cats aren't *exactly* Animals, so we can't love him! 😿
This is annoying because Cats *are* Animals. They support every operation
an Animal supports, so intuitively `love` shouldn't care if we pass it a `Cat`.
We should be able to just **forget** the non-animal parts of our `Cat`, as they
aren't necessary to love it.
This is exactly the problem that *subtyping* is intended to fix. Because Cats are just
Animals **and more**, we say Cat is a *subtype* of Animal (because Cats are a *subset*
of all the Animals). Equivalently, we say that Animal is a *supertype* of Cat.
With subtypes, we can tweak our overly strict static type system
with a simple rule: anywhere a value of type `T` is expected, we will also
accept values that are subtypes of `T`.
Or more concretely: anywhere an Animal is expected, a Cat or Dog will also work.
As we will see throughout the rest of this section, subtyping is a lot more complicated
and subtle than this, but this simple rule is a very good 99% intuition. And unless you
write unsafe code, the compiler will automatically handle all the corner cases for you.
But this is the Rustonomicon. We're writing unsafe code, so we need to understand how
this stuff really works, and how we can mess it up.
The core problem is that this rule, naively applied, will lead to *meowing Dogs*. That is,
we can convince someone that a Dog is actually a Cat. This completely destroys the fabric
of our static type system, making it worse than useless (and leading to Undefined Behaviour).
Here's a simple example of this happening when we apply subtyping in a completely naive
"find and replace" way.
```rust,ignore
fn evil_feeder(pet: &mut Animal) {
let spike: Dog = ...;
// `pet` is an Animal, and Dog is a subtype of Animal,
// so this should be fine, right..?
*pet = spike;
}
fn main() {
let mut mr_snuggles: Cat = ...;
evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog
mr_snuggles.meow(); // OH NO, MEOWING DOG!
}
```
Clearly, we need a more robust system than "find and replace". That system is *variance*,
which is a set of rules governing how subtyping should compose. Most importantly, variance
defines situations where subtyping should be disabled.
But before we get into variance, let's take a quick peek at where subtyping actually occurs in
Rust: *lifetimes*!
> NOTE: The typed-ness of lifetimes is a fairly arbitrary construct that some
> disagree with. However it simplifies our analysis to treat lifetimes
> and types uniformly.
Lifetimes are just regions of code, and regions can be partially ordered with the *contains*
(outlives) relationship. Subtyping on lifetimes is in terms of that relationship:
if `'big: 'small` ("big contains small" or "big outlives small"), then `'big` is a subtype
of `'small`. This is a large source of confusion, because it seems backwards
to many: the bigger region is a *subtype* of the smaller region. But it makes
sense if you consider our Animal example: *Cat* is an Animal *and more*,
sense if you consider our Animal example: Cat is an Animal *and more*,
just as `'big` is `'small` *and more*.
Put another way, if someone wants a reference that lives for `'small`,
usually what they actually mean is that they want a reference that lives
for *at least* `'small`. They don't actually care if the lifetimes match
exactly. For this reason `'static`, the forever lifetime, is a subtype
of every lifetime.
exactly. So it should be ok for us to **forget** that something lives for
`'big` and only remember that it lives for `'small`.
Higher-ranked lifetimes are also subtypes of every concrete lifetime. This is
because taking an arbitrary lifetime is strictly more general than taking a
specific one.
The meowing dog problem for lifetimes will result in us being able to
store a short-lived reference in a place that expects a longer-lived one,
creating a dangling reference and letting us use-after-free.
(The typed-ness of lifetimes is a fairly arbitrary construct that some
disagree with. However it simplifies our analysis to treat lifetimes
and types uniformly.)
However you can't write a function that takes a value of type `'a`! Lifetimes
are always just part of another type, so we need a way of handling that.
To handle it, we need to talk about *variance*.
It will be useful to note that `'static`, the forever lifetime, is a subtype of
every lifetime because by definition it outlives everything. We will be using
this relationship in later examples to keep them as simple as possible.
With all that said, we still have no idea how to actually *use* subtyping of lifetimes,
because nothing ever has type `'a`. Lifetimes only occur as part of some larger type
like `&'a u32` or `IterMut<'a, u32>`. To apply lifetime subtyping, we need to know
how to compose subtyping. Once again, we need *variance*.
@ -59,200 +141,288 @@ To handle it, we need to talk about *variance*.
Variance is where things get a bit complicated.
Variance is a property that *type constructors* have with respect to their
arguments. A type constructor in Rust is a generic type with unbound arguments.
For instance `Vec` is a type constructor that takes a `T` and returns a
arguments. A type constructor in Rust is any generic type with unbound arguments.
For instance `Vec` is a type constructor that takes a type `T` and returns
`Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a
lifetime, and a type to point to.
> NOTE: For convenience we will often refer to `F<T>` as a type constructor just so
> that we can easily talk about `T`. Hopefully this is clear in context.
A type constructor F's *variance* is how the subtyping of its inputs affects the
subtyping of its outputs. There are three kinds of variance in Rust:
subtyping of its outputs. There are three kinds of variance in Rust. Given two
types `Sub` and `Super`, where `Sub` is a subtype of `Super`:
* F is *covariant* over `T` if `T` being a subtype of `U` implies
`F<T>` is a subtype of `F<U>` (subtyping "passes through")
* F is *contravariant* over `T` if `T` being a subtype of `U` implies
`F<U>` is a subtype of `F<T>` (subtyping is "inverted")
* F is *invariant* over `T` otherwise (no subtyping relation can be derived)
* `F` is *covariant* if `F<Sub>` is a subtype of `F<Super>` (subtyping "passes through")
* `F` is *contravariant* if `F<Super>` is a subtype of `F<Sub>` (subtyping is "inverted")
* `F` is *invariant* otherwise (no subtyping relationship exists)
It should be noted that covariance is *far* more common and important than
contravariance in Rust. The existence of contravariance in Rust can mostly
be ignored.
If `F` has multiple type parameters, we can talk about the individual variances
by saying that, for example, `F<T, U>` is covariant over `T` and invariant over `U`.
Some important variances (which we will explain in detail below):
It is very useful to keep in mind that covariance is, in practical terms, "the"
variance. Almost all consideration of variance is in terms of whether something
should be covariant or invariant. Actually witnessing contravariance is quite difficult
in Rust, though it does in fact exist.
* `&'a T` is covariant over `'a` and `T` (as is `*const T` by metaphor)
* `&'a mut T` is covariant over `'a` but invariant over `T`
* `fn(T) -> U` is **contra**variant over `T`, but covariant over `U`
* `Box`, `Vec`, and all other collections are covariant over the types of
their contents
* `UnsafeCell<T>`, `Cell<T>`, `RefCell<T>`, `Mutex<T>` and all other
interior mutability types are invariant over T (as is `*mut T` by metaphor)
Here is a table of important variances which the rest of this section will be devoted
to trying to explain:
To understand why these variances are correct and desirable, we will consider
several examples.
| | | 'a | T | U |
|---|-----------------|:---------:|:-----------------:|:---------:|
| * | `&'a T ` | covariant | covariant | |
| * | `&'a mut T` | covariant | invariant | |
| * | `Box<T>` | | covariant | |
| | `Vec<T>` | | covariant | |
| * | `UnsafeCell<T>` | | invariant | |
| | `Cell<T>` | | invariant | |
| * | `fn(T) -> U` | | **contra**variant | covariant |
| | `*const T` | | covariant | |
| | `*mut T` | | invariant | |
We have already covered why `&'a T` should be covariant over `'a` when
introducing subtyping: it's desirable to be able to pass longer-lived things
where shorter-lived things are needed.
The types with \*'s are the ones we will be focusing on, as they are in
some sense "fundamental". All the others can be understood by analogy to the others:
Similar reasoning applies to why it should be covariant over T: it's reasonable
to be able to pass `&&'static str` where an `&&'a str` is expected. The
additional level of indirection doesn't change the desire to be able to pass
longer lived things where shorter lived things are expected.
* Vec and all other owning pointers and collections follow the same logic as Box
* Cell and all other interior mutability types follow the same logic as UnsafeCell
* `*const` follows the logic of `&T`
* `*mut` follows the logic of `&mut T` (or `UnsafeCell<T>`)
However this logic doesn't apply to `&mut`. To see why `&mut` should
be invariant over T, consider the following code:
> NOTE: the *only* source of contravariance in the language is the arguments to
> a function, which is why it really doesn't come up much in practice. Invoking
> contravariance involves higher-order programming with function pointers that
> take references with specific lifetimes (as opposed to the usual "any lifetime",
> which gets into higher rank lifetimes, which work independently of subtyping).
Ok, that's enough type theory! Let's try to apply the concept of variance to Rust
and look at some examples.
First off, let's revisit the meowing dog example:
```rust,ignore
fn overwrite<T: Copy>(input: &mut T, new: &mut T) {
*input = *new;
fn evil_feeder(pet: &mut Animal) {
let spike: Dog = ...;
// `pet` is an Animal, and Dog is a subtype of Animal,
// so this should be fine, right..?
*pet = spike;
}
fn main() {
let mut forever_str: &'static str = "hello";
{
let string = String::from("world");
overwrite(&mut forever_str, &mut &*string);
}
// Oops, printing free'd memory
println!("{}", forever_str);
let mut mr_snuggles: Cat = ...;
evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog
mr_snuggles.meow(); // OH NO, MEOWING DOG!
}
```
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 we look at our table of variances, we see that `&mut T` is *invariant* over `T`.
As it turns out, this completely fixes the issue! With invariance, the fact that
Cat is a subtype of Animal doesn't matter; `&mut Cat` still won't be a subtype of
`&mut Animal`. The static type checker will then correctly stop us from passing
a Cat into `evil_feeder`.
But, if `&mut T` was covariant 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 print it! Therefore `&mut` should be invariant.
The soundness of subtyping is based on the idea that it's ok to forget unnecessary
details. But with references, there's always someone that remembers those details:
the value being referenced. That value expects those details to keep being true,
and may behave incorrectly if its expectations are violated.
This is the general theme of variance vs invariance: if variance would allow you
to store a short-lived value in a longer-lived slot, then invariance must be used.
The problem with making `&mut T` covariant over `T` is that it gives us the power
to modify the original value *when we don't remember all of its constraints*.
And so, we can make someone have a Dog when they're certain they still have a Cat.
More generally, the soundness of subtyping and variance is based on the idea that its ok to
forget details, but with mutable references there's always someone (the original
value being referenced) that remembers the forgotten details and will assume
that those details haven't changed. If we do something to invalidate those details,
the original location can behave unsoundly.
With that established, we can easily see why `&T` being covariant over `T` *is*
sound: it doesn't let you modify the value, only look at it. Without any way to
mutate, there's no way for us to mess with any details. We can also see why
`UnsafeCell` and all the other interior mutability types must be invariant: they
make `&T` work like `&mut T`!
However it *is* sound for `&'a mut T` to be covariant over `'a`. The key difference
between `'a` and T is that `'a` is a property of the reference itself,
while T is something the reference is borrowing. If you change T's type, then
the source still remembers the original type. However if you change the
lifetime's type, no one but the reference knows this information, so it's fine.
Put another way: `&'a mut T` owns `'a`, but only *borrows* T.
Now what about the lifetime on references? Why is it ok for both kinds of references
to be covariant over their lifetimes? Well, here's a two-pronged argument:
`Box` and `Vec` are interesting cases because they're covariant, but you can
definitely store values in them! This is where Rust's typesystem allows it to
be a bit more clever than others. To understand why it's sound for owning
containers to be covariant over their contents, we must consider
the two ways in which a mutation may occur: by-value or by-reference.
First and foremost, subtyping references based on their lifetimes is *the entire point
of subtyping in Rust*. The only reason we have subtyping is so we can pass
long-lived things where short-lived things are expected. So it better work!
If mutation is by-value, then the old location that remembers extra details is
moved out of, meaning it can't use the value anymore. So we simply don't need to
worry about anyone remembering dangerous details. Put another way, applying
subtyping when passing by-value *destroys details forever*. For example, this
compiles and is fine:
Second, and more seriously, lifetimes are only a part of the reference itself. The
type of the referent is shared knowledge, which is why adjusting that type in only
one place (the reference) can lead to issues. But if you shrink down a reference's
lifetime when you hand it to someone, that lifetime information isn't shared in
anyway. There are now two independent references with independent lifetimes.
There's no way to mess with original reference's lifetime using the other one.
Or rather, the only way to mess with someone's lifetime is to build a meowing dog.
But as soon as you try to build a meowing dog, the lifetime should be wrapped up
in an invariant type, preventing the lifetime from being shrunk. To understand this
better, let's port the meowing dog problem over to real Rust.
In the meowing dog problem we take a subtype (Cat), convert it into a supertype
(Animal), and then use that fact to overwrite the subtype with a value that satisfies
the constraints of the supertype but not the subtype (Dog).
So with lifetimes, we want to take a long-lived thing, convert it into a
short-lived thing, and then use that to write something that doesn't live long
enough into the place expecting something long-lived.
Here it is:
```rust,ignore
fn evil_feeder<T>(input: &mut T, val: T) {
*input = val;
}
fn main() {
let mut mr_snuggles: &'static str = "meow! :3"; // mr. snuggles forever!!
{
let spike = String::from("bark! >:V");
let spike_str: &str = &spike; // Only lives for the block
evil_feeder(&mut mr_snuggles, spike_str); // EVIL!
}
println!("{}", mr_snuggles); // Use after free?
}
```
And what do we get when we run this?
```text
error[E0597]: `spike` does not live long enough
--> src/main.rs:9:32
|
9 | let spike_str: &str = &spike;
| ^^^^^ borrowed value does not live long enough
10 | evil_feeder(&mut mr_snuggles, spike_str);
11 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
```
Good, it doesn't compile! Let's break down what's happening here in detail.
First let's look at the new `evil_feeder` function:
```rust
fn get_box<'a>(str: &'a str) -> Box<&'a str> {
// String literals are `&'static str`s, but it's fine for us to
// "forget" this and let the caller think the string won't live that long.
Box::new("hello")
fn evil_feeder<T>(input: &mut T, val: T) {
*input = val;
}
```
If mutation is by-reference, then our container is passed as `&mut Vec<T>`. But
`&mut` is invariant over its value, so `&mut Vec<T>` is actually invariant over `T`.
So the fact that `Vec<T>` is covariant over `T` doesn't matter at all when
mutating by-reference.
All it does it take a mutable reference and a value and overwrite the referent with it.
What's important about this function is that it creates a type equality constraint. It
clearly says in its signature the referent and the value must be the *exact same* type.
But being covariant still allows `Box` and `Vec` to be weakened when shared
immutably. So you can pass a `&Vec<&'static str>` where a `&Vec<&'a str>` is
expected.
Meanwhile, in the caller we pass in `&mut &'static str` and `&'spike_str str`.
The invariance of the cell types can be seen as follows: `&` is like an `&mut`
for a cell, because you can still store values in them through an `&`. Therefore
cells must be invariant to avoid lifetime smuggling.
Because `&mut T` is invariant over `T`, the compiler concludes it can't apply any subtyping
to the first argument, and so `T` must be exactly `&'static str`.
`fn` is the most subtle case because they have mixed variance, and in fact are
the only source of **contra**variance. To see why `fn(T) -> U` should be contravariant
over T, consider the following function signature:
The other argument is only an `&'a str`, which *is* covariant over `'a`. So the compiler
adopts a constraint: `&'spike_str str` must be a subtype of `&'static str` (inclusive),
which in turn implies `'spike_str` must be a subtype of `'static` (inclusive). Which is to say,
`'spike_str` must contain `'static`. But only one thing contains `'static` -- `'static` itself!
This is why we get an error when we try to assign `&spike` to `spike_str`. The
compiler has worked backwards to conclude `spike_str` must live forever, and `&spike`
simply can't live that long.
So even though references are covariant over their lifetimes, they "inherit" invariance
whenever they're put into a context that could do something bad with that. In this case,
we inherited invariance as soon as we put our reference inside an `&mut T`.
As it turns out, the argument for why it's ok for Box (and Vec, Hashmap, etc.) to
be covariant is pretty similar to the argument for why it's ok for
lifetimes to be covariant: as soon as you try to stuff them in something like a
mutable reference, they inherit invariance and you're prevented from doing anything
bad.
However Box makes it easier to focus on by-value aspect of references that we
partially glossed over.
Unlike a lot of languages which allow values to be freely aliased at all times,
Rust has a very strict rule: if you're allowed to mutate or move a value, you
are guaranteed to be the only one with access to it.
Consider the following code:
```rust,ignore
// 'a is derived from some parent scope
fn foo(&'a str) -> usize;
let mr_snuggles: Box<Cat> = ..;
let spike: Box<Dog> = ..;
let mut pet: Box<Animal>;
pet = mr_snuggles;
pet = spike;
```
This signature claims that it can handle any `&str` that lives at least as
long as `'a`. Now if this signature was **co**variant over `&'a str`, that
would mean
There is no problem at all with the fact that we have forgotten that `mr_snuggles` was a Cat,
or that we overwrote him with a Dog, because as soon as we moved mr_snuggles to a variable
that only knew he was an Animal, **we destroyed the only thing in the universe that
remembered he was a Cat**!
In contrast to the argument about immutable references being soundly covariant because they
don't let you change anything, owned values can be covariant because they make you
change *everything*. There is no connection between old locations and new locations.
Applying by-value subtyping is an irreversible act of knowledge destruction, and
without any memory of how things used to be, no one can be tricked into acting on
that old information!
Only one thing left to explain: function pointers.
To see why `fn(T) -> U` should be covariant over `U`, consider the following signature:
```rust,ignore
fn foo(&'static str) -> usize;
fn get_animal() -> Animal;
```
could be provided in its place, as it would be a subtype. However this function
has a stronger requirement: it says that it can only handle `&'static str`s,
and nothing else. Giving `&'a str`s to it would be unsound, as it's free to
assume that what it's given lives forever. Therefore functions definitely shouldn't
be **co**variant over their arguments.
However if we flip it around and use **contra**variance, it *does* work! If
something expects a function which can handle strings that live forever,
it makes perfect sense to instead provide a function that can handle
strings that live for *less* than forever. So
This function claims to produce an Animal. As such, it is perfectly valid to
provide a function with the following signature instead:
```rust,ignore
fn foo(&'a str) -> usize;
fn get_animal() -> Cat;
```
can be passed where
After all, Cats are Animals, so always producing a Cat is a perfectly valid way
to produce Animals. Or to relate it back to real Rust: if we need a function
that is supposed to produce something that lives for `'short`, it's perfectly
fine for it to produce something that lives for `'long`. We don't care, we can
just forget that fact.
However, the same logic does not apply to *arguments*. Consider trying to satisfy:
```rust,ignore
fn foo(&'static str) -> usize;
fn handle_animal(Animal);
```
is expected.
To see why `fn(T) -> U` should be **co**variant over U, consider the following
function signature:
with
```rust,ignore
// 'a is derived from some parent scope
fn foo(usize) -> &'a str;
fn handle_animal(Cat);
```
This signature claims that it will return something that outlives `'a`. It is
therefore completely reasonable to provide
The first function can accept Dogs, but the second function absolutely can't.
Covariance doesn't work here. But if we flip it around, it actually *does*
work! If we need a function that can handle Cats, a function that can handle *any*
Animal will surely work fine. Or to relate it back to real Rust: if we need a
function that can handle anything that lives for at least `'long`, it's perfectly
fine for it to be able to handle anything that lives for at least `'short`.
```rust,ignore
fn foo(usize) -> &'static str;
```
And that's why function types, unlike anything else in the language, are
**contra**variant over their arguments.
in its place, as it does indeed return things that outlive `'a`. Therefore
functions are covariant over their return type.
`*const` has the exact same semantics as `&`, so variance follows. `*mut` on the
other hand can dereference to an `&mut` whether shared or not, so it is marked
as invariant just like cells.
This is all well and good for the types the standard library provides, but
Now, this is all well and good for the types the standard library provides, but
how is variance determined for type that *you* define? A struct, informally
speaking, inherits the variance of its fields. If a struct `Foo`
has a generic argument `A` that is used in a field `a`, then Foo's variance
over `A` is exactly `a`'s variance. However if `A` is used in multiple fields:
speaking, inherits the variance of its fields. If a struct `MyType`
has a generic argument `A` that is used in a field `a`, then MyType's variance
over `A` is exactly `a`'s variance over `A`.
* If all uses of A are covariant, then Foo is covariant over A
* If all uses of A are contravariant, then Foo is contravariant over A
* Otherwise, Foo is invariant over A
However if `A` is used in multiple fields:
* If all uses of `A` are covariant, then MyType is covariant over `A`
* If all uses of `A` are contravariant, then MyType is contravariant over `A`
* Otherwise, MyType is invariant over `A`
```rust
use std::cell::Cell;
struct Foo<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H, In, Out, Mixed> {
struct MyType<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H, In, Out, Mixed> {
a: &'a A, // covariant over 'a and A
b: &'b mut B, // covariant over 'b and invariant over B
@ -272,3 +442,4 @@ struct Foo<'a, 'b, A: 'a, B: 'b, C, D, E, F, G, H, In, Out, Mixed> {
k2: Mixed, // invariant over Mixed, because invariance wins all conflicts
}
```

View File

@ -294,11 +294,21 @@ impl OperandValue<'ll> {
bx.store_with_flags(val, dest.llval, dest.align, flags);
}
OperandValue::Pair(a, b) => {
for (i, &x) in [a, b].iter().enumerate() {
let llptr = bx.struct_gep(dest.llval, i as u64);
let val = base::from_immediate(bx, x);
bx.store_with_flags(val, llptr, dest.align, flags);
}
let (a_scalar, b_scalar) = match dest.layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
_ => bug!("store_with_flags: invalid ScalarPair layout: {:#?}", dest.layout)
};
let b_offset = a_scalar.value.size(bx.cx).abi_align(b_scalar.value.align(bx.cx));
let llptr = bx.struct_gep(dest.llval, 0);
let val = base::from_immediate(bx, a);
let align = dest.align;
bx.store_with_flags(val, llptr, align, flags);
let llptr = bx.struct_gep(dest.llval, 1);
let val = base::from_immediate(bx, b);
let align = dest.align.restrict_for_offset(b_offset);
bx.store_with_flags(val, llptr, align, flags);
}
}
}

View File

@ -150,9 +150,10 @@ impl PlaceRef<'ll, 'tcx> {
});
OperandValue::Immediate(base::to_immediate(bx, llval, self.layout))
} else if let layout::Abi::ScalarPair(ref a, ref b) = self.layout.abi {
let load = |i, scalar: &layout::Scalar| {
let b_offset = a.value.size(bx.cx).abi_align(b.value.align(bx.cx));
let load = |i, scalar: &layout::Scalar, align| {
let llptr = bx.struct_gep(self.llval, i as u64);
let load = bx.load(llptr, self.align);
let load = bx.load(llptr, align);
scalar_load_metadata(load, scalar);
if scalar.is_bool() {
bx.trunc(load, Type::i1(bx.cx))
@ -160,7 +161,10 @@ impl PlaceRef<'ll, 'tcx> {
load
}
};
OperandValue::Pair(load(0, a), load(1, b))
OperandValue::Pair(
load(0, a, self.align),
load(1, b, self.align.restrict_for_offset(b_offset)),
)
} else {
OperandValue::Ref(self.llval, None, self.align)
};

View File

@ -91,7 +91,7 @@ pub fn spawn_thread_pool<F: FnOnce(config::Options) -> R + sync::Send, R: sync::
let config = ThreadPoolBuilder::new()
.num_threads(Session::query_threads_from_opts(&opts))
.deadlock_handler(|| unsafe { ty::query::handle_deadlock() })
.stack_size(16 * 1024 * 1024);
.stack_size(::STACK_SIZE);
let with_pool = move |pool: &ThreadPool| {
pool.install(move || f(opts))

View File

@ -1460,6 +1460,11 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec<as
}
}
// Temporarily have stack size set to 32MB to deal with various crates with long method
// chains or deep syntax trees.
// FIXME(oli-obk): get https://github.com/rust-lang/rust/pull/55617 the finish line
const STACK_SIZE: usize = 32 * 1024 * 1024; // 32MB
/// Runs `f` in a suitable thread for running `rustc`; returns a `Result` with either the return
/// value of `f` or -- if a panic occurs -- the panic value.
///
@ -1469,9 +1474,6 @@ pub fn in_named_rustc_thread<F, R>(name: String, f: F) -> Result<R, Box<dyn Any
where F: FnOnce() -> R + Send + 'static,
R: Send + 'static,
{
// Temporarily have stack size set to 16MB to deal with nom-using crates failing
const STACK_SIZE: usize = 16 * 1024 * 1024; // 16MB
#[cfg(all(unix, not(target_os = "haiku")))]
let spawn_thread = unsafe {
// Fetch the current resource limits

Some files were not shown because too many files have changed in this diff Show More