mirror of
https://git.proxmox.com/git/rustc
synced 2025-08-03 12:04:48 +00:00
New upstream version 1.31.0+dfsg1
This commit is contained in:
parent
13cf67c4bb
commit
450edc1f0b
@ -1 +1 @@
|
||||
42053f9f07c91cbaad78afe459851a435b346673
|
||||
abe02cefd6cd1916df62ad7dc80161bea50b72e8
|
35
src/Cargo.lock
generated
35
src/Cargo.lock
generated
@ -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"
|
||||
|
@ -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" }
|
||||
|
@ -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,
|
||||
|
@ -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";
|
||||
|
@ -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"
|
||||
|
13
src/doc/edition-guide/.travis.yml
Normal file
13
src/doc/edition-guide/.travis.yml
Normal 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
|
201
src/doc/edition-guide/LICENSE-APACHE
Normal file
201
src/doc/edition-guide/LICENSE-APACHE
Normal 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.
|
25
src/doc/edition-guide/LICENSE-MIT
Normal file
25
src/doc/edition-guide/LICENSE-MIT
Normal 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.
|
63
src/doc/edition-guide/README.md
Normal file
63
src/doc/edition-guide/README.md
Normal file
@ -0,0 +1,63 @@
|
||||
# The Rust Edition Guide
|
||||
|
||||
[](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
|
||||
```
|
5
src/doc/edition-guide/book.toml
Normal file
5
src/doc/edition-guide/book.toml
Normal file
@ -0,0 +1,5 @@
|
||||
[book]
|
||||
authors = ["The Rust Project Developers"]
|
||||
multilingual = false
|
||||
src = "src"
|
||||
title = "The Edition Guide"
|
27
src/doc/edition-guide/deploy.sh
Normal file
27
src/doc/edition-guide/deploy.sh
Normal 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
|
86
src/doc/edition-guide/src/SUMMARY.md
Normal file
86
src/doc/edition-guide/src/SUMMARY.md
Normal 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)
|
35
src/doc/edition-guide/src/editions/creating-a-new-project.md
Normal file
35
src/doc/edition-guide/src/editions/creating-a-new-project.md
Normal 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.
|
68
src/doc/edition-guide/src/editions/index.md
Normal file
68
src/doc/edition-guide/src/editions/index.md
Normal 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
|
||||
```
|
@ -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!
|
16
src/doc/edition-guide/src/introduction.md
Normal file
16
src/doc/edition-guide/src/introduction.md
Normal 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.
|
18
src/doc/edition-guide/src/rust-2015/index.md
Normal file
18
src/doc/edition-guide/src/rust-2015/index.md
Normal 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!
|
@ -0,0 +1,38 @@
|
||||
# Cargo can use a local registry replacement
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,54 @@
|
||||
# `cargo check` for faster checking
|
||||
|
||||

|
||||
|
||||
`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 |
|
@ -0,0 +1,34 @@
|
||||
# `cargo install` for easy installation of tools
|
||||
|
||||

|
||||
|
||||
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
|
||||
```
|
@ -0,0 +1,18 @@
|
||||
# `cargo new` defaults to a binary project
|
||||
|
||||

|
||||
|
||||
`cargo new` will now default to generating a binary, rather than a library.
|
||||
We try to keep Cargo’s 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 don’t
|
||||
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.
|
||||
It’s not just new Rustaceans though; even very long-time community members
|
||||
have said that they find this default surprising. As such, we’ve changed it,
|
||||
and it now defaults to `--bin`.
|
@ -0,0 +1,21 @@
|
||||
# `cargo rustc` for passing arbitrary flags to rustc
|
||||
|
||||

|
||||
|
||||
`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`.
|
@ -0,0 +1,30 @@
|
||||
# Cargo workspaces for multi-package projects
|
||||
|
||||

|
||||
|
||||
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).
|
@ -0,0 +1,25 @@
|
||||
# Crates.io disallows wildcard dependencies
|
||||
|
||||

|
||||
|
||||
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.
|
@ -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.
|
@ -0,0 +1,22 @@
|
||||
# Multi-file examples
|
||||
|
||||

|
||||
|
||||
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
|
||||
```
|
@ -0,0 +1,35 @@
|
||||
# Replacing dependencies with patch
|
||||
|
||||

|
||||
|
||||
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 what’s it look like? Let’s 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, we’d 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).
|
@ -0,0 +1,7 @@
|
||||
# async/await for easier concurrency
|
||||
|
||||

|
||||
|
||||
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!
|
@ -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].
|
@ -0,0 +1,26 @@
|
||||
# `loop`s can break with a value
|
||||
|
||||

|
||||
|
||||
`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.
|
@ -0,0 +1,17 @@
|
||||
# 128 bit integers
|
||||
|
||||

|
||||
|
||||
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!
|
@ -0,0 +1,55 @@
|
||||
# Choosing alignment with the repr attribute
|
||||
|
||||

|
||||
|
||||
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 you’re 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.
|
@ -0,0 +1,49 @@
|
||||
# Field init shorthand
|
||||
|
||||

|
||||
|
||||
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,
|
||||
};
|
||||
```
|
@ -0,0 +1,72 @@
|
||||
# `..=` for inclusive ranges
|
||||
|
||||

|
||||
|
||||
Since well before Rust 1.0, you’ve 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
|
||||
```
|
||||
|
||||
That’s 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.
|
6
src/doc/edition-guide/src/rust-2018/data-types/index.md
Normal file
6
src/doc/edition-guide/src/rust-2018/data-types/index.md
Normal 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].
|
@ -0,0 +1,33 @@
|
||||
# "Operator-equals" are now implementable
|
||||
|
||||

|
||||
|
||||
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 }`.
|
@ -0,0 +1,60 @@
|
||||
# `union` for an unsafe form of `enum`
|
||||
|
||||

|
||||
|
||||
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 can’t check this for us, that means reading a union’s 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.
|
||||
|
||||
There’s 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.
|
@ -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].
|
@ -0,0 +1,37 @@
|
||||
# New editions of the "the book"
|
||||
|
||||
 for drafts of the second edition
|
||||
|
||||
 for the final version of the second edition
|
||||
|
||||
 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 we’ve
|
||||
gained from teaching people Rust. You’ll find brand-new explanations for a
|
||||
lot of Rust’s 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.
|
@ -0,0 +1,11 @@
|
||||
# `std::os` has documentation for all platforms
|
||||
|
||||

|
||||
|
||||
The `std::os` module contains operating system specific functionality. You’ll
|
||||
now see more than just linux, the platform we build the documentation on.
|
||||
|
||||
We’ve 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.
|
@ -0,0 +1,33 @@
|
||||
# The Rust Bookshelf
|
||||
|
||||
, 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
|
||||
|
||||

|
||||
|
||||
Historically, Cargo’s docs were hosted on <http://doc.crates.io>, which
|
||||
doesn’t 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 wouldn’t yet. <https://doc.rust-lang.org/cargo> is the new home
|
||||
of Cargo’s docs, and <http://doc.crates.io> now redirects there.
|
||||
|
||||
## The `rustdoc` book
|
||||
|
||||

|
||||
|
||||
Rustdoc, our documentation tool, now has a guide at <https://doc.rust-lang.org/rustdoc>.
|
||||
|
||||
## Rust By Example
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,10 @@
|
||||
# The Rustonomicon
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,18 @@
|
||||
# Aborting on panic
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,80 @@
|
||||
# Controlling panics with `std::panic`
|
||||
|
||||

|
||||
|
||||
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.
|
@ -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].
|
@ -0,0 +1,129 @@
|
||||
# `?` in `main` and tests
|
||||
|
||||

|
||||
|
||||
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).
|
@ -0,0 +1,120 @@
|
||||
# The `?` operator for easier error handling
|
||||
|
||||
 for `Result<T, E>`
|
||||
|
||||
 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.
|
8
src/doc/edition-guide/src/rust-2018/index.md
Normal file
8
src/doc/edition-guide/src/rust-2018/index.md
Normal 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.
|
38
src/doc/edition-guide/src/rust-2018/macros/at-most-once.md
Normal file
38
src/doc/edition-guide/src/rust-2018/macros/at-most-once.md
Normal 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);
|
||||
)?
|
||||
}
|
||||
}
|
||||
```
|
49
src/doc/edition-guide/src/rust-2018/macros/custom-derive.md
Normal file
49
src/doc/edition-guide/src/rust-2018/macros/custom-derive.md
Normal file
@ -0,0 +1,49 @@
|
||||
# Custom Derive
|
||||
|
||||

|
||||
|
||||
In Rust, you’ve 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).
|
6
src/doc/edition-guide/src/rust-2018/macros/index.md
Normal file
6
src/doc/edition-guide/src/rust-2018/macros/index.md
Normal 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].
|
271
src/doc/edition-guide/src/rust-2018/macros/macro-changes.md
Normal file
271
src/doc/edition-guide/src/rust-2018/macros/macro-changes.md
Normal file
@ -0,0 +1,271 @@
|
||||
# Macro changes
|
||||
|
||||

|
||||
|
||||
## `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. :)
|
@ -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].
|
@ -0,0 +1,16 @@
|
||||
# More visibility modifiers
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,35 @@
|
||||
# Nested imports with `use`
|
||||
|
||||

|
||||
|
||||
A new way to write `use` statements has been added to Rust: nested import
|
||||
groups. If you’ve 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.
|
@ -0,0 +1,390 @@
|
||||
# Path clarity
|
||||
|
||||

|
||||
 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.
|
@ -0,0 +1,68 @@
|
||||
# Raw identifiers
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,61 @@
|
||||
# Default match bindings
|
||||
|
||||

|
||||
|
||||
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.
|
@ -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].
|
@ -0,0 +1,72 @@
|
||||
# `T: 'a` inference in structs
|
||||
|
||||

|
||||
|
||||
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).
|
@ -0,0 +1,75 @@
|
||||
# Lifetime elision in impl
|
||||
|
||||

|
||||
|
||||
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
|
@ -0,0 +1,83 @@
|
||||
# Non-lexical lifetimes
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,41 @@
|
||||
# Simpler lifetimes in `static` and `const`
|
||||
|
||||

|
||||
|
||||
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"];
|
||||
# }
|
||||
```
|
@ -0,0 +1,103 @@
|
||||
# `'_`, the anonymous lifetime
|
||||
|
||||

|
||||
|
||||
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).
|
@ -0,0 +1,18 @@
|
||||
# cdylib crates for C interoperability
|
||||
|
||||
 for `rustc`
|
||||
|
||||
 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.
|
@ -0,0 +1,35 @@
|
||||
# Global allocators
|
||||
|
||||

|
||||
|
||||
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).
|
@ -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].
|
@ -0,0 +1,31 @@
|
||||
# libcore for low-level Rust
|
||||
|
||||

|
||||
|
||||
Rust’s standard library is two-tiered: there’s 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. Rust’s `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/).
|
@ -0,0 +1,18 @@
|
||||
# MSVC toolchain support
|
||||
|
||||

|
||||
|
||||
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
|
||||
```
|
@ -0,0 +1,45 @@
|
||||
# MUSL support for fully static binaries
|
||||
|
||||

|
||||
|
||||
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!
|
@ -0,0 +1,28 @@
|
||||
# WebAssembly support
|
||||
|
||||
 for `emscripten`
|
||||
|
||||
 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.
|
@ -0,0 +1,19 @@
|
||||
# Documentation tests can now compile-fail
|
||||
|
||||

|
||||
|
||||
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.
|
6
src/doc/edition-guide/src/rust-2018/rustdoc/index.md
Normal file
6
src/doc/edition-guide/src/rust-2018/rustdoc/index.md
Normal 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].
|
@ -0,0 +1,16 @@
|
||||
# Rustdoc uses CommonMark
|
||||
|
||||
 for support by default
|
||||
|
||||
 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.
|
@ -0,0 +1,212 @@
|
||||
# Rustup for managing Rust versions
|
||||
|
||||
 (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
|
||||
|
||||

|
||||
|
||||
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
|
||||
|
||||

|
||||
|
||||
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.
|
108
src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md
Normal file
108
src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md
Normal file
@ -0,0 +1,108 @@
|
||||
# SIMD for faster computing
|
||||
|
||||

|
||||
|
||||
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, we’re 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`.
|
||||
That’d be much faster!
|
||||
|
||||
While stable Rust has always been able to take advantage of
|
||||
autovectorization, sometimes, the compiler just isn’t 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 don’t 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
|
||||
we’re 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 don’t,
|
||||
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. Here’s 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, you’d 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!
|
91
src/doc/edition-guide/src/rust-2018/slice-patterns.md
Normal file
91
src/doc/edition-guide/src/rust-2018/slice-patterns.md
Normal file
@ -0,0 +1,91 @@
|
||||
# Slice patterns
|
||||
|
||||

|
||||
|
||||
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].
|
@ -0,0 +1,35 @@
|
||||
# An attribute for deprecation
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,49 @@
|
||||
# Improved error messages
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,23 @@
|
||||
# Incremental Compilation
|
||||
|
||||

|
||||
|
||||
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 you’re
|
||||
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 you’ve changed the code. The idea with incremental
|
||||
compilation is that you only need to compile the code you’ve 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! Don’t 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.
|
@ -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].
|
@ -0,0 +1,117 @@
|
||||
# Associated constants
|
||||
|
||||

|
||||
|
||||
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, they’re 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
|
||||
you’d 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, you’d have to write this:
|
||||
|
||||
```rust
|
||||
trait Float {
|
||||
fn nan() -> Self;
|
||||
fn infinity() -> Self;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
This is slightly unwieldy, but more importantly, because they’re 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.
|
@ -0,0 +1,42 @@
|
||||
# `dyn Trait` for trait objects
|
||||
|
||||

|
||||
|
||||
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.
|
@ -0,0 +1,168 @@
|
||||
# `impl Trait` for returning complex types with ease
|
||||
|
||||

|
||||
|
||||
`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).
|
@ -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].
|
@ -0,0 +1,28 @@
|
||||
# More container types support trait objects
|
||||
|
||||

|
||||
|
||||
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>`.
|
@ -0,0 +1,23 @@
|
||||
# No more anonymous trait parameters
|
||||
|
||||

|
||||
|
||||
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);
|
||||
}
|
||||
```
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 aren’t 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
|
||||
|
@ -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> {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
};
|
||||
|
@ -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))
|
||||
|
@ -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
Loading…
Reference in New Issue
Block a user