From 450edc1f0b42243b48cb6f7da20709a470ad96ed Mon Sep 17 00:00:00 2001 From: Ximin Luo Date: Fri, 14 Dec 2018 21:27:17 -0800 Subject: [PATCH] New upstream version 1.31.0+dfsg1 --- git-commit-hash | 2 +- src/Cargo.lock | 35 +- src/Cargo.toml | 2 +- src/bootstrap/builder.rs | 3 +- src/bootstrap/doc.rs | 1 + src/ci/run.sh | 2 +- src/doc/edition-guide/.travis.yml | 13 + src/doc/edition-guide/LICENSE-APACHE | 201 +++++++ src/doc/edition-guide/LICENSE-MIT | 25 + src/doc/edition-guide/README.md | 63 +++ src/doc/edition-guide/book.toml | 5 + src/doc/edition-guide/deploy.sh | 27 + src/doc/edition-guide/src/SUMMARY.md | 86 +++ .../src/editions/creating-a-new-project.md | 35 ++ src/doc/edition-guide/src/editions/index.md | 68 +++ ...ng-an-existing-project-to-a-new-edition.md | 144 +++++ src/doc/edition-guide/src/introduction.md | 16 + src/doc/edition-guide/src/rust-2015/index.md | 18 + ...go-can-use-a-local-registry-replacement.md | 38 ++ .../cargo-check-for-faster-checking.md | 54 ++ ...-install-for-easy-installation-of-tools.md | 34 ++ .../cargo-new-defaults-to-a-binary-project.md | 18 + ...tc-for-passing-arbitrary-flags-to-rustc.md | 21 + ...o-workspaces-for-multi-package-projects.md | 30 ++ ...ates-io-disallows-wildcard-dependencies.md | 25 + .../rust-2018/cargo-and-crates-io/index.md | 6 + .../multi-file-examples.md | 22 + .../replacing-dependencies-with-patch.md | 35 ++ .../async-await-for-easier-concurrency.md | 7 + .../src/rust-2018/control-flow/index.md | 6 + .../loops-can-break-with-a-value.md | 26 + .../rust-2018/data-types/128-bit-integers.md | 17 + ...osing-alignment-with-the-repr-attribute.md | 55 ++ .../data-types/field-init-shorthand.md | 49 ++ .../rust-2018/data-types/inclusive-ranges.md | 72 +++ .../src/rust-2018/data-types/index.md | 6 + .../operator-equals-are-now-implementable.md | 33 ++ .../union-for-an-unsafe-form-of-enum.md | 60 +++ .../src/rust-2018/documentation/index.md | 6 + .../documentation/new-editions-of-the-book.md | 37 ++ ...-os-has-documentation-for-all-platforms.md | 11 + .../documentation/the-rust-bookshelf.md | 33 ++ .../documentation/the-rustonomicon.md | 10 + .../aborting-on-panic.md | 18 + .../controlling-panics-with-std-panic.md | 80 +++ .../error-handling-and-panics/index.md | 6 + .../question-mark-in-main-and-tests.md | 129 +++++ ...mark-operator-for-easier-error-handling.md | 120 +++++ src/doc/edition-guide/src/rust-2018/index.md | 8 + .../src/rust-2018/macros/at-most-once.md | 38 ++ .../src/rust-2018/macros/custom-derive.md | 49 ++ .../src/rust-2018/macros/index.md | 6 + .../src/rust-2018/macros/macro-changes.md | 271 ++++++++++ .../src/rust-2018/module-system/index.md | 6 + .../more-visibility-modifiers.md | 16 + .../module-system/nested-imports-with-use.md | 35 ++ .../rust-2018/module-system/path-clarity.md | 390 ++++++++++++++ .../module-system/raw-identifiers.md | 68 +++ .../default-match-bindings.md | 61 +++ .../ownership-and-lifetimes/index.md | 6 + .../inference-in-structs.md | 72 +++ .../lifetime-elision-in-impl.md | 75 +++ .../non-lexical-lifetimes.md | 83 +++ .../simpler-lifetimes-in-static-and-const.md | 41 ++ .../the-anonymous-lifetime.md | 103 ++++ .../cdylib-crates-for-c-interoperability.md | 18 + .../global-allocators.md | 35 ++ .../platform-and-target-support/index.md | 6 + .../libcore-for-low-level-rust.md | 31 ++ .../msvc-toolchain-support.md | 18 + .../musl-support-for-fully-static-binaries.md | 45 ++ .../webassembly-support.md | 28 + ...ocumentation-tests-can-now-compile-fail.md | 19 + .../src/rust-2018/rustdoc/index.md | 6 + .../rustdoc/rustdoc-uses-commonmark.md | 16 + .../rustup-for-managing-rust-versions.md | 212 ++++++++ .../rust-2018/simd-for-faster-computing.md | 108 ++++ .../src/rust-2018/slice-patterns.md | 91 ++++ .../an-attribute-for-deprecation.md | 35 ++ .../the-compiler/improved-error-messages.md | 49 ++ ...emental-compilation-for-faster-compiles.md | 23 + .../src/rust-2018/the-compiler/index.md | 6 + .../trait-system/associated-constants.md | 117 ++++ .../dyn-trait-for-trait-objects.md | 42 ++ ...t-for-returning-complex-types-with-ease.md | 168 ++++++ .../src/rust-2018/trait-system/index.md | 6 + ...e-container-types-support-trait-objects.md | 28 + .../rust-2018/trait-system/no-anon-params.md | 23 + src/doc/nomicon/src/README.md | 14 +- src/doc/nomicon/src/data.md | 14 + src/doc/nomicon/src/drop-flags.md | 2 +- src/doc/nomicon/src/exotic-sizes.md | 112 +++- src/doc/nomicon/src/other-reprs.md | 52 +- src/doc/nomicon/src/phantom-data.md | 6 +- src/doc/nomicon/src/repr-rust.md | 42 +- src/doc/nomicon/src/subtyping.md | 503 ++++++++++++------ src/librustc_codegen_llvm/mir/operand.rs | 20 +- src/librustc_codegen_llvm/mir/place.rs | 10 +- src/librustc_driver/driver.rs | 2 +- src/librustc_driver/lib.rs | 8 +- .../borrow_check/nll/region_infer/mod.rs | 2 +- src/librustc_resolve/lib.rs | 2 +- src/librustc_resolve/resolve_imports.rs | 4 +- src/librustc_typeck/check/wfcheck.rs | 4 +- src/test/codegen/issue-56267-2.rs | 18 + src/test/codegen/issue-56267.rs | 18 + src/test/ui/imports/issue-56263.rs | 8 + .../propagate-multiple-requirements.rs | 25 + .../propagate-multiple-requirements.stderr | 17 + .../rust-2018/auxiliary/edition-lint-paths.rs | 11 + .../ui/rust-2018/edition-lint-paths-2018.rs | 10 + version | 2 +- 112 files changed, 4895 insertions(+), 279 deletions(-) create mode 100644 src/doc/edition-guide/.travis.yml create mode 100644 src/doc/edition-guide/LICENSE-APACHE create mode 100644 src/doc/edition-guide/LICENSE-MIT create mode 100644 src/doc/edition-guide/README.md create mode 100644 src/doc/edition-guide/book.toml create mode 100644 src/doc/edition-guide/deploy.sh create mode 100644 src/doc/edition-guide/src/SUMMARY.md create mode 100644 src/doc/edition-guide/src/editions/creating-a-new-project.md create mode 100644 src/doc/edition-guide/src/editions/index.md create mode 100644 src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md create mode 100644 src/doc/edition-guide/src/introduction.md create mode 100644 src/doc/edition-guide/src/rust-2015/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-can-use-a-local-registry-replacement.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-install-for-easy-installation-of-tools.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-new-defaults-to-a-binary-project.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-workspaces-for-multi-package-projects.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/multi-file-examples.md create mode 100644 src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/replacing-dependencies-with-patch.md create mode 100644 src/doc/edition-guide/src/rust-2018/control-flow/async-await-for-easier-concurrency.md create mode 100644 src/doc/edition-guide/src/rust-2018/control-flow/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/control-flow/loops-can-break-with-a-value.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/128-bit-integers.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/choosing-alignment-with-the-repr-attribute.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/field-init-shorthand.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/inclusive-ranges.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/operator-equals-are-now-implementable.md create mode 100644 src/doc/edition-guide/src/rust-2018/data-types/union-for-an-unsafe-form-of-enum.md create mode 100644 src/doc/edition-guide/src/rust-2018/documentation/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/documentation/new-editions-of-the-book.md create mode 100644 src/doc/edition-guide/src/rust-2018/documentation/std-os-has-documentation-for-all-platforms.md create mode 100644 src/doc/edition-guide/src/rust-2018/documentation/the-rust-bookshelf.md create mode 100644 src/doc/edition-guide/src/rust-2018/documentation/the-rustonomicon.md create mode 100644 src/doc/edition-guide/src/rust-2018/error-handling-and-panics/aborting-on-panic.md create mode 100644 src/doc/edition-guide/src/rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md create mode 100644 src/doc/edition-guide/src/rust-2018/error-handling-and-panics/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md create mode 100644 src/doc/edition-guide/src/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md create mode 100644 src/doc/edition-guide/src/rust-2018/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/macros/at-most-once.md create mode 100644 src/doc/edition-guide/src/rust-2018/macros/custom-derive.md create mode 100644 src/doc/edition-guide/src/rust-2018/macros/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/macros/macro-changes.md create mode 100644 src/doc/edition-guide/src/rust-2018/module-system/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/module-system/more-visibility-modifiers.md create mode 100644 src/doc/edition-guide/src/rust-2018/module-system/nested-imports-with-use.md create mode 100644 src/doc/edition-guide/src/rust-2018/module-system/path-clarity.md create mode 100644 src/doc/edition-guide/src/rust-2018/module-system/raw-identifiers.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/default-match-bindings.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/inference-in-structs.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/lifetime-elision-in-impl.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/simpler-lifetimes-in-static-and-const.md create mode 100644 src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/global-allocators.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/libcore-for-low-level-rust.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/msvc-toolchain-support.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md create mode 100644 src/doc/edition-guide/src/rust-2018/platform-and-target-support/webassembly-support.md create mode 100644 src/doc/edition-guide/src/rust-2018/rustdoc/documentation-tests-can-now-compile-fail.md create mode 100644 src/doc/edition-guide/src/rust-2018/rustdoc/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/rustdoc/rustdoc-uses-commonmark.md create mode 100644 src/doc/edition-guide/src/rust-2018/rustup-for-managing-rust-versions.md create mode 100644 src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md create mode 100644 src/doc/edition-guide/src/rust-2018/slice-patterns.md create mode 100644 src/doc/edition-guide/src/rust-2018/the-compiler/an-attribute-for-deprecation.md create mode 100644 src/doc/edition-guide/src/rust-2018/the-compiler/improved-error-messages.md create mode 100644 src/doc/edition-guide/src/rust-2018/the-compiler/incremental-compilation-for-faster-compiles.md create mode 100644 src/doc/edition-guide/src/rust-2018/the-compiler/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/associated-constants.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/dyn-trait-for-trait-objects.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/index.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/more-container-types-support-trait-objects.md create mode 100644 src/doc/edition-guide/src/rust-2018/trait-system/no-anon-params.md create mode 100644 src/test/codegen/issue-56267-2.rs create mode 100644 src/test/codegen/issue-56267.rs create mode 100644 src/test/ui/imports/issue-56263.rs create mode 100644 src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs create mode 100644 src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr create mode 100644 src/test/ui/rust-2018/edition-lint-paths-2018.rs diff --git a/git-commit-hash b/git-commit-hash index 250f51f9dd..b09edf56f5 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -42053f9f07c91cbaad78afe459851a435b346673 \ No newline at end of file +abe02cefd6cd1916df62ad7dc80161bea50b72e8 \ No newline at end of file diff --git a/src/Cargo.lock b/src/Cargo.lock index 8533fde98e..fed6a3d098 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -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" diff --git a/src/Cargo.toml b/src/Cargo.toml index e8c44ea57c..ee997a6ca4 100644 --- a/src/Cargo.toml +++ b/src/Cargo.toml @@ -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" } diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index ab2c7c2325..02e9ca9250 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -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, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index cb3b61792b..85767936fc 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -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"; diff --git a/src/ci/run.sh b/src/ci/run.sh index f51199de6e..324c873dd3 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -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" diff --git a/src/doc/edition-guide/.travis.yml b/src/doc/edition-guide/.travis.yml new file mode 100644 index 0000000000..363fea9a47 --- /dev/null +++ b/src/doc/edition-guide/.travis.yml @@ -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 diff --git a/src/doc/edition-guide/LICENSE-APACHE b/src/doc/edition-guide/LICENSE-APACHE new file mode 100644 index 0000000000..f8e5e5ea03 --- /dev/null +++ b/src/doc/edition-guide/LICENSE-APACHE @@ -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. \ No newline at end of file diff --git a/src/doc/edition-guide/LICENSE-MIT b/src/doc/edition-guide/LICENSE-MIT new file mode 100644 index 0000000000..1351ec0708 --- /dev/null +++ b/src/doc/edition-guide/LICENSE-MIT @@ -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. \ No newline at end of file diff --git a/src/doc/edition-guide/README.md b/src/doc/edition-guide/README.md new file mode 100644 index 0000000000..8643dbb6b8 --- /dev/null +++ b/src/doc/edition-guide/README.md @@ -0,0 +1,63 @@ +# The Rust Edition Guide + +[![Build Status](https://travis-ci.org/rust-lang-nursery/edition-guide.svg?branch=master)](https://travis-ci.org/rust-lang-nursery/edition-guide) + +This book explains the concept of "editions", major new eras in [Rust]'s +development. You can [read the book +online](https://rust-lang-nursery.github.io/edition-guide/). + +[Rust]: https://www.rust-lang.org/ + +## License + +The Edition Guide is dual licensed under `MIT`/`Apache2`, just like Rust itself. +See the `LICENSE-*` files in this repository for more details. + +## Building locally + +You can also build the book and read it locally if you'd like. + +### Requirements + +Building the book requires [mdBook]. To get it: + +[mdBook]: https://github.com/azerupi/mdBook + +```bash +$ cargo install mdbook +``` + +### Building + +To build the book, do this: + +```bash +$ mdbook build +``` + +The output will be in the `book` subdirectory. To check it out, open it in +your web browser. + +_Firefox:_ + +```shell +$ firefox book/index.html # Linux +$ open -a "Firefox" book/index.html # OS X +$ Start-Process "firefox.exe" .\book\index.html # Windows (PowerShell) +$ start firefox.exe .\book\index.html # Windows (Cmd) +``` + +_Chrome:_ + +```shell +$ google-chrome book/index.html # Linux +$ open -a "Google Chrome" book/index.html # OS X +$ Start-Process "chrome.exe" .\book\index.html # Windows (PowerShell) +$ start chrome.exe .\book\index.html # Windows (Cmd) +``` + +To run the tests: + +```bash +$ mdbook test +``` diff --git a/src/doc/edition-guide/book.toml b/src/doc/edition-guide/book.toml new file mode 100644 index 0000000000..1b4bf93f60 --- /dev/null +++ b/src/doc/edition-guide/book.toml @@ -0,0 +1,5 @@ +[book] +authors = ["The Rust Project Developers"] +multilingual = false +src = "src" +title = "The Edition Guide" diff --git a/src/doc/edition-guide/deploy.sh b/src/doc/edition-guide/deploy.sh new file mode 100644 index 0000000000..512fa00363 --- /dev/null +++ b/src/doc/edition-guide/deploy.sh @@ -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 diff --git a/src/doc/edition-guide/src/SUMMARY.md b/src/doc/edition-guide/src/SUMMARY.md new file mode 100644 index 0000000000..52d95220b1 --- /dev/null +++ b/src/doc/edition-guide/src/SUMMARY.md @@ -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) \ No newline at end of file diff --git a/src/doc/edition-guide/src/editions/creating-a-new-project.md b/src/doc/edition-guide/src/editions/creating-a-new-project.md new file mode 100644 index 0000000000..e42f1e8634 --- /dev/null +++ b/src/doc/edition-guide/src/editions/creating-a-new-project.md @@ -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 "] +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 "] +edition = "2015" + +[dependencies] +``` + +This will build your package in Rust 2015. diff --git a/src/doc/edition-guide/src/editions/index.md b/src/doc/edition-guide/src/editions/index.md new file mode 100644 index 0000000000..1f94fa2115 --- /dev/null +++ b/src/doc/edition-guide/src/editions/index.md @@ -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 +``` \ No newline at end of file diff --git a/src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md b/src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md new file mode 100644 index 0000000000..cce67be79c --- /dev/null +++ b/src/doc/edition-guide/src/editions/transitioning-an-existing-project-to-a-new-edition.md @@ -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); +} +``` + +This code uses an anonymous parameter, that `Box`. 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); +} +``` + +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 "] +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); +} +``` + +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); +} +``` + +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! diff --git a/src/doc/edition-guide/src/introduction.md b/src/doc/edition-guide/src/introduction.md new file mode 100644 index 0000000000..7479cce7a0 --- /dev/null +++ b/src/doc/edition-guide/src/introduction.md @@ -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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2015/index.md b/src/doc/edition-guide/src/rust-2015/index.md new file mode 100644 index 0000000000..8c18891484 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2015/index.md @@ -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! \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-can-use-a-local-registry-replacement.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-can-use-a-local-registry-replacement.md new file mode 100644 index 0000000000..bd49becee2 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-can-use-a-local-registry-replacement.md @@ -0,0 +1,38 @@ +# Cargo can use a local registry replacement + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +Cargo finds its packages in a "source". The default source is [crates.io](https://crates.io). However, you +can choose a different source in your `.cargo/config`: + +```toml +[source.crates-io] +replace-with = 'my-awesome-registry' + +[source.my-awesome-registry] +registry = 'https://github.com/my-awesome/registry-index' +``` + +This configuration means that instead of using crates.io, Cargo will query +the `my-awesome-registry` source instead (configured to a different index +here). This alternate source *must be the exact same* as the crates.io index. +Cargo assumes that replacement sources are exact 1:1 mirrors in this respect, +and the following support is designed around that assumption. + +When generating a lock file for crate using a replacement registry, the +original registry will be encoded into the lock file. For example in the +configuration above, all lock files will still mention crates.io as the +registry that packages originated from. This semantically represents how +crates.io is the source of truth for all crates, and this is upheld because +all replacements have a 1:1 correspondance. + +Overall, this means that no matter what replacement source you're working +with, you can ship your lock file to anyone else and you'll all still have +verifiably reproducible builds! + +This has enabled tools like +[`cargo-vendor`](https://github.com/alexcrichton/cargo-vendor) and +[`cargo-local-registry`](https://github.com/alexcrichton/cargo-local-registry), +which are often useful for "offline builds." They prepare the list of all +Rust dependencies ahead of time, which lets you ship them to a build machine +with ease. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.md new file mode 100644 index 0000000000..323297d889 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.md @@ -0,0 +1,54 @@ +# `cargo check` for faster checking + +![Minimum Rust version: 1.16](https://img.shields.io/badge/Minimum%20Rust%20Version-1.16-brightgreen.svg) + +`cargo check` is a new subcommand should speed up the development +workflow in many cases. + +What does it do? Let's take a step back and talk about how `rustc` compiles +your code. Compilation has many "passes", that is, there are many distinct +steps that the compiler takes on the road from your source code to producing +the final binary. However, you can think of this process in two big steps: +first, `rustc` does all of its safety checks, makes sure your syntax is +correct, all that stuff. Second, once it's satisfied that everything is in +order, it produces the actual binary code that you end up executing. + +It turns out that that second step takes a lot of time. And most of the time, +it's not neccesary. That is, when you're working on some Rust code, many +developers will get into a workflow like this: + +1. Write some code. +2. Run `cargo build` to make sure it compiles. +3. Repeat 1-2 as needed. +4. Run `cargo test` to make sure your tests pass. +5. Try the binary yourself +6. GOTO 1. + +In step two, you never actually run your code. You're looking for feedback +from the compiler, not to actually run the binary. `cargo check` supports +exactly this use-case: it runs all of the compiler's checks, but doesn't +produce the final binary. To use it: + +```console +$ cargo check +``` + +where you may normally `cargo build`. The workflow now looks like: + +1. Write some code. +2. Run `cargo check` to make sure it compiles. +3. Repeat 1-2 as needed. +4. Run `cargo test` to make sure your tests pass. +5. Run `cargo build` to build a binary and try it yourself +6. GOTO 1. + + +So how much speedup do you actually get? Like most performance related +questions, the answer is "it depends." Here are some very un-scientific +benchmarks at the time of writing. + +| build | performance | check performance | speedup | +|--------|-------------|-------------------|---------| +| initial compile | 11s | 5.6s | 1.96x | +| second compile (no changes) | 3s | 1.9s | 1.57x | +| third compile with small change | 5.8s | 3s | 1.93x | \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-install-for-easy-installation-of-tools.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-install-for-easy-installation-of-tools.md new file mode 100644 index 0000000000..d45e84e93d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-install-for-easy-installation-of-tools.md @@ -0,0 +1,34 @@ +# `cargo install` for easy installation of tools + +![Minimum Rust version: 1.5](https://img.shields.io/badge/Minimum%20Rust%20Version-1.5-brightgreen.svg) + +Cargo has grown a new `install` command. This is intended to be used for installing +new subcommands for Cargo, or tools for Rust developers. This doesn't replace the need +to build real, native packages for end-users on the platforms you support. + +For example, this guide is created with [`mdbook`](https://crates.io/crates/mdbook). You +can install it on your system with + +```console +$ cargo install mdbook +``` + +And then use it with + +```console +$ mdbook --help +``` + +As an example of extending Cargo, you can use the [`cargo-update`](https://crates.io/crates/cargo-update) +package. To install it: + +```console +$ cargo install cargo-update +``` + +This will allow you to use this command, which checks everything you've `cargo install`'d and +updates it to the latest version: + +```console +$ cargo install-update -a +``` \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-new-defaults-to-a-binary-project.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-new-defaults-to-a-binary-project.md new file mode 100644 index 0000000000..5e12c0b052 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-new-defaults-to-a-binary-project.md @@ -0,0 +1,18 @@ +# `cargo new` defaults to a binary project + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +`cargo new` will now default to generating a binary, rather than a library. +We try to keep 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`. diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md new file mode 100644 index 0000000000..8a13e004fd --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-rustc-for-passing-arbitrary-flags-to-rustc.md @@ -0,0 +1,21 @@ +# `cargo rustc` for passing arbitrary flags to rustc + +![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg) + +`cargo rustc` is a new subcommand for Cargo that allows you to pass arbitrary +`rustc` flags through Cargo. + +For example, Cargo does not have a way to pass unstable flags built-in. But +if we'd like to use `print-type-sizes` to see what layout information our +types have. We can run this: + +```console +$ cargo rustc -- -Z print-type-sizes +``` + +And we'll get a bunch of output describing the size of our types. + +## Note + +`cargo rustc` only passes these flags to invocations of your crate, and not to any `rustc` +invocations used to build dependencies. If you'd like to do that, see `$RUSTFLAGS`. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-workspaces-for-multi-package-projects.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-workspaces-for-multi-package-projects.md new file mode 100644 index 0000000000..c2189e43d3 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/cargo-workspaces-for-multi-package-projects.md @@ -0,0 +1,30 @@ +# Cargo workspaces for multi-package projects + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +Cargo used to have two levels of organization: + +* A *package* contains one or more crates +* A crate has one or more modules + +Cargo now has an additional level: + +* A *workspace* contains one or more packages + +This can be useful for larger projects. For example, [the `futures` package] +is a *workspace* that contains many related packages: + +* futures +* futures-util +* futures-io +* futures-channel + +and more. + +[the `futures` package]: https://github.com/rust-lang-nursery/futures-rs + +Workspaces allow these packages to be developed individually, but they share +a single set of dependencies, and therefore have a single target directory +and a single `Cargo.lock`. + +For more details about workspaces, please see [the Cargo documentation](https://doc.rust-lang.org/stable/cargo/reference/manifest.html#the-workspace-section). diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.md new file mode 100644 index 0000000000..ac8cd5a9af --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/crates-io-disallows-wildcard-dependencies.md @@ -0,0 +1,25 @@ +# Crates.io disallows wildcard dependencies + +![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg) + +Crates.io will not allow you to upload a package with a wildcard dependency. +In other words, these: + +```toml +[dependencies] +regex = "*" +``` + +A wildcard dependency means that you work with any possible version of your +dependency. This is highly unlikely to be true, and would cause unnecessary +breakage in the ecosystem. + +Instead, depend on a version range. For example, `^` is the default, so +you could use + +```toml +[dependencies] +regex = "1.0.0" +``` + +instead. `>`, `<=`, and all of the other, non-`*` ranges work as well. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/index.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/index.md new file mode 100644 index 0000000000..231c83a374 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/index.md @@ -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. diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/multi-file-examples.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/multi-file-examples.md new file mode 100644 index 0000000000..d73a552455 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/multi-file-examples.md @@ -0,0 +1,22 @@ +# Multi-file examples + +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) + +Cargo has an `examples` feature for showing people how to use your package. +By putting individual files inside of the top-level `examples` directory, you +can create multiple examples. + +But what if your example is too big for a single file? Cargo supports adding +sub-directories inside of `examples`, and looks for a `main.rs` inside of +them to build the example. It looks like this: + +```text +my-package + └──src + └── lib.rs // code here + └──examples + └── simple-example.rs // a single-file example + └── complex-example + └── helper.rs + └── main.rs // a more complex example that also uses `helper` as a submodule +``` diff --git a/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/replacing-dependencies-with-patch.md b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/replacing-dependencies-with-patch.md new file mode 100644 index 0000000000..a0ba636c27 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/cargo-and-crates-io/replacing-dependencies-with-patch.md @@ -0,0 +1,35 @@ +# Replacing dependencies with patch + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +The `[patch]` section of your `Cargo.toml` can be used when you want to +override certain parts of your dependency graph. + +> Cargo has a `[replace]` feature that is similar; while we don't intend to deprecate +> or remove `[replace]`, you should prefer `[patch]` in all circumstances. + +So 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). \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/control-flow/async-await-for-easier-concurrency.md b/src/doc/edition-guide/src/rust-2018/control-flow/async-await-for-easier-concurrency.md new file mode 100644 index 0000000000..1ba53bdc02 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/control-flow/async-await-for-easier-concurrency.md @@ -0,0 +1,7 @@ +# async/await for easier concurrency + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +The initial release of Rust 2018 won't ship with `async`/`await` support, but +we have reserved the keywords so that a future release will contain them. +We'll update this page when it's closer to shipping! \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/control-flow/index.md b/src/doc/edition-guide/src/rust-2018/control-flow/index.md new file mode 100644 index 0000000000..a274d7883c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/control-flow/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/control-flow/loops-can-break-with-a-value.md b/src/doc/edition-guide/src/rust-2018/control-flow/loops-can-break-with-a-value.md new file mode 100644 index 0000000000..b76a75fe75 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/control-flow/loops-can-break-with-a-value.md @@ -0,0 +1,26 @@ +# `loop`s can break with a value + +![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg) + +`loop`s can now break with a value: + +```rust +// old code +let x; + +loop { + x = 7; + break; +} + +// new code +let x = loop { break 7; }; +``` + +Rust has traditionally positioned itself as an “expression oriented +language”, that is, most things are expressions that evaluate to a value, +rather than statements. `loop` stuck out as strange in this way, as it was +previously a statement. + +For now, this only applies to `loop`, and not things like `while` or `for`. +It's not clear yet, but we may add this to those in the future. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/128-bit-integers.md b/src/doc/edition-guide/src/rust-2018/data-types/128-bit-integers.md new file mode 100644 index 0000000000..68f0616216 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/128-bit-integers.md @@ -0,0 +1,17 @@ +# 128 bit integers + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +A very simple feature: Rust now has 128 bit integers! + +```rust +let x: i128 = 0; +let y: u128 = 0; +``` + +These are twice the size of `u64`, and so can hold more values. More specifically, + +* `u128`: `0` - `340,282,366,920,938,463,463,374,607,431,768,211,455` +* `i128`: `−170,141,183,460,469,231,731,687,303,715,884,105,728` - `170,141,183,460,469,231,731,687,303,715,884,105,727` + +Whew! \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/choosing-alignment-with-the-repr-attribute.md b/src/doc/edition-guide/src/rust-2018/data-types/choosing-alignment-with-the-repr-attribute.md new file mode 100644 index 0000000000..b2624de698 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/choosing-alignment-with-the-repr-attribute.md @@ -0,0 +1,55 @@ +# Choosing alignment with the repr attribute + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +From [Wikipedia](https://en.wikipedia.org/wiki/Data_structure_alignment): + +> The CPU in modern computer hardware performs reads and writes to memory +> most efficiently when the data is naturally aligned, which generally means +> that the data address is a multiple of the data size. Data alignment refers +> to aligning elements according to their natural alignment. To ensure natural +> alignment, it may be necessary to insert some padding between structure +> elements or after the last element of a structure. + +The `#[repr]` attribute has a new parameter, `align`, that sets the alignment of your struct: + +```rust +struct Number(i32); + +assert_eq!(std::mem::align_of::(), 4); +assert_eq!(std::mem::size_of::(), 4); + +#[repr(align(16))] +struct Align16(i32); + +assert_eq!(std::mem::align_of::(), 16); +assert_eq!(std::mem::size_of::(), 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/field-init-shorthand.md b/src/doc/edition-guide/src/rust-2018/data-types/field-init-shorthand.md new file mode 100644 index 0000000000..85eb71576c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/field-init-shorthand.md @@ -0,0 +1,49 @@ +# Field init shorthand + +![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg) + +In older Rust, when initializing a struct, you must always give the full set of `key: value` pairs +for its fields: + +```rust +struct Point { + x: i32, + y: i32, +} + +let a = 5; +let b = 6; + +let p = Point { + x: a, + y: b, +}; +``` + +However, often these variables would have the same names as the fields. So you'd end up +with code that looks like this: + +```rust,ignore +let p = Point { + x: x, + y: y, +}; +``` + +Now, if the variable is of the same name, you don't have to write out both, just write out the key: + +```rust +struct Point { + x: i32, + y: i32, +} + +let x = 5; +let y = 6; + +// new +let p = Point { + x, + y, +}; +``` \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/inclusive-ranges.md b/src/doc/edition-guide/src/rust-2018/data-types/inclusive-ranges.md new file mode 100644 index 0000000000..e25d2a982d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/inclusive-ranges.md @@ -0,0 +1,72 @@ +# `..=` for inclusive ranges + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Since well before Rust 1.0, 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/index.md b/src/doc/edition-guide/src/rust-2018/data-types/index.md new file mode 100644 index 0000000000..369680bd2f --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/operator-equals-are-now-implementable.md b/src/doc/edition-guide/src/rust-2018/data-types/operator-equals-are-now-implementable.md new file mode 100644 index 0000000000..19390fa3c4 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/operator-equals-are-now-implementable.md @@ -0,0 +1,33 @@ +# "Operator-equals" are now implementable + +![Minimum Rust version: 1.8](https://img.shields.io/badge/Minimum%20Rust%20Version-1.8-brightgreen.svg) + +The various “operator equals” operators, such as `+=` and `-=`, are +implementable via various traits. For example, to implement `+=` on +a type of your own: + +```rust +use std::ops::AddAssign; + +#[derive(Debug)] +struct Count { + value: i32, +} + +impl AddAssign for Count { + fn add_assign(&mut self, other: Count) { + self.value += other.value; + } +} + +fn main() { + let mut c1 = Count { value: 1 }; + let c2 = Count { value: 5 }; + + c1 += c2; + + println!("{:?}", c1); +} +``` + +This will print `Count { value: 6 }`. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/data-types/union-for-an-unsafe-form-of-enum.md b/src/doc/edition-guide/src/rust-2018/data-types/union-for-an-unsafe-form-of-enum.md new file mode 100644 index 0000000000..a0bea75839 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/data-types/union-for-an-unsafe-form-of-enum.md @@ -0,0 +1,60 @@ +# `union` for an unsafe form of `enum` + +![Minimum Rust version: 1.19](https://img.shields.io/badge/Minimum%20Rust%20Version-1.19-brightgreen.svg) + +Rust now supports `unions`: + +```rust +union MyUnion { + f1: u32, + f2: f32, +} +``` + +Unions are kind of like enums, but they are “untagged”. Enums have a “tag” +that stores which variant is the correct one at runtime; unions don't have +this tag. + +Since we can interpret the data held in the union using the wrong variant and +Rust 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. diff --git a/src/doc/edition-guide/src/rust-2018/documentation/index.md b/src/doc/edition-guide/src/rust-2018/documentation/index.md new file mode 100644 index 0000000000..60726060e6 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/documentation/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/documentation/new-editions-of-the-book.md b/src/doc/edition-guide/src/rust-2018/documentation/new-editions-of-the-book.md new file mode 100644 index 0000000000..1b30935b09 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/documentation/new-editions-of-the-book.md @@ -0,0 +1,37 @@ +# New editions of the "the book" + +![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-red.svg) for drafts of the second edition + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) for the final version of the second edition + +![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-red.svg) for drafts of the 2018 edition + +We've distributed a copy of "The Rust Programming Language," affectionately +nicknamed "the book", with every version of Rust since Rust 1.0. + +However, because it was written before Rust 1.0, it started showing its age. +Many parts of the book are vague, because it was written before the true +details were nailed down for the 1.0 release. It didn't do a fantastic job of +teaching lifetimes. + +Starting with Rust 1.18, we shipped drafts of a second edition of the book. +The final version was shipped with Rust 1.26. The new edition is a complete +re-write from the ground up, using the last two years of knowledge 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/documentation/std-os-has-documentation-for-all-platforms.md b/src/doc/edition-guide/src/rust-2018/documentation/std-os-has-documentation-for-all-platforms.md new file mode 100644 index 0000000000..5be8f01bc5 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/documentation/std-os-has-documentation-for-all-platforms.md @@ -0,0 +1,11 @@ +# `std::os` has documentation for all platforms + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +The `std::os` module contains operating system specific functionality. 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/documentation/the-rust-bookshelf.md b/src/doc/edition-guide/src/rust-2018/documentation/the-rust-bookshelf.md new file mode 100644 index 0000000000..e91627ac1f --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/documentation/the-rust-bookshelf.md @@ -0,0 +1,33 @@ +# The Rust Bookshelf + +![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg), each book is different. + +As Rust's documentation has grown, we've gained far more than just "The book" +and the reference. We now have a collection of various long-form docs, +nicknamed "the Rust Bookshelf." Different resources are added at various +times, and we're adding new ones as more get written. + +## The Cargo book + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +Historically, Cargo’s docs were hosted on , 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. is the new home +of Cargo’s docs, and now redirects there. + +## The `rustdoc` book + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +Rustdoc, our documentation tool, now has a guide at . + +## Rust By Example + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +Rust by Example used to live at , but now is part of the Bookshelf! +It can be found at . RBE lets you learn Rust through +short code examples and exercises, as opposed to the lengthy prose of The Book. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/documentation/the-rustonomicon.md b/src/doc/edition-guide/src/rust-2018/documentation/the-rustonomicon.md new file mode 100644 index 0000000000..514520c02c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/documentation/the-rustonomicon.md @@ -0,0 +1,10 @@ +# The Rustonomicon + +![Minimum Rust version: 1.3](https://img.shields.io/badge/Minimum%20Rust%20Version-1.3-brightgreen.svg) + +We now have a draft book, [The Rustonomicon: the Dark Arts of Advanced and +Unsafe Rust Programming](https://doc.rust-lang.org/stable/nomicon/). + +From the title, I'm sure you can guess: this book discusses some advanced +topics, including `unsafe`. It's a must-read for anyone who's working at the +lowest levels with Rust. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/aborting-on-panic.md b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/aborting-on-panic.md new file mode 100644 index 0000000000..d28138c45e --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/aborting-on-panic.md @@ -0,0 +1,18 @@ +# Aborting on panic + +![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg) + +By default, Rust programs will unwind the stack when a `panic!` happens. If you'd prefer an +immediate abort instead, you can configure this in `Cargo.toml`: + +```toml +[profile.debug] +panic = "abort" + +[profile.release] +panic = "abort" +``` + +Why might you choose to do this? By removing support for unwinding, you'll +get smaller binaries. You will lose the ability to catch panics. Which choice +is right for you depends on exactly what you're doing. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md new file mode 100644 index 0000000000..6c1bf63465 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/controlling-panics-with-std-panic.md @@ -0,0 +1,80 @@ +# Controlling panics with `std::panic` + +![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg) + +There is a `std::panic` module, which includes methods for halting the +unwinding process started by a panic: + +```rust +use std::panic; + +let result = panic::catch_unwind(|| { + println!("hello!"); +}); +assert!(result.is_ok()); + +let result = panic::catch_unwind(|| { + panic!("oh no!"); +}); +assert!(result.is_err()); +``` + +In general, Rust distinguishes between two ways that an operation can fail: + +- Due to an *expected problem*, like a file not being found. +- Due to an *unexpected problem*, like an index being out of bounds for an array. + +Expected problems usually arise from conditions that are outside of your +control; robust code should be prepared for anything its environment might throw +at it. In Rust, expected problems are handled via [the `Result` type][result], +which allows a function to return information about the problem to its caller, +which can then handle the error in a fine-grained way. + +[result]: http://doc.rust-lang.org/std/result/index.html + +Unexpected problems are *bugs*: they arise due to a contract or assertion being +violated. Since they are unexpected, it doesn't make sense to handle them in a +fine-grained way. Instead, Rust employs a "fail fast" approach by *panicking*, +which by default unwinds the stack (running destructors but no other code) of +the thread which discovered the error. Other threads continue running, but will +discover the panic any time they try to communicate with the panicked thread +(whether through channels or shared memory). Panics thus abort execution up to +some "isolation boundary", with code on the other side of the boundary still +able to run, and perhaps to "recover" from the panic in some very coarse-grained +way. A server, for example, does not necessarily need to go down just because of +an assertion failure in one of its threads. + +It's also worth noting that programs may choose to *abort* instead of unwind, +and so catching panics may not work. If your code relies on `catch_unwind`, you +should add this to your Cargo.toml: + +```toml +[profile.debug] +panic = "unwind" + +[profile.release] +panic = "unwind" +``` + +If any of your users choose to abort, they'll get a compile-time failure. + +The `catch_unwind` API offers a way to introduce new isolation boundaries +*within a thread*. There are a couple of key motivating examples: + +* Embedding Rust in other languages +* Abstractions that manage threads +* Test frameworks, because tests may panic and you don't want that to kill the test runner + +For the first case, unwinding across a language boundary is undefined behavior, +and often leads to segfaults in practice. Allowing panics to be caught means +that you can safely expose Rust code via a C API, and translate unwinding into +an error on the C side. + +For the second case, consider a threadpool library. If a thread in the pool +panics, you generally don't want to kill the thread itself, but rather catch the +panic and communicate it to the client of the pool. The `catch_unwind` API is +paired with `resume_unwind`, which can then be used to restart the panicking +process on the client of the pool, where it belongs. + +In both cases, you're introducing a new isolation boundary within a thread, and +then translating the panic into some other form of error elsewhere. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/index.md b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/index.md new file mode 100644 index 0000000000..f9792db799 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md new file mode 100644 index 0000000000..5a81005589 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/question-mark-in-main-and-tests.md @@ -0,0 +1,129 @@ +# `?` in `main` and tests + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Rust's error handling revolves around returning `Result` 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> { + // 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 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). diff --git a/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md new file mode 100644 index 0000000000..d521a4a15a --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/error-handling-and-panics/the-question-mark-operator-for-easier-error-handling.md @@ -0,0 +1,120 @@ +# The `?` operator for easier error handling + +![Minimum Rust version: 1.13](https://img.shields.io/badge/Minimum%20Rust%20Version-1.13-brightgreen.svg) for `Result` + +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) for `Option` + +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 { + 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 { + 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 { + 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`s, but also with `Option`. 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. diff --git a/src/doc/edition-guide/src/rust-2018/index.md b/src/doc/edition-guide/src/rust-2018/index.md new file mode 100644 index 0000000000..ee982334b1 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/index.md @@ -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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/macros/at-most-once.md b/src/doc/edition-guide/src/rust-2018/macros/at-most-once.md new file mode 100644 index 0000000000..fb38610d52 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/macros/at-most-once.md @@ -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); + )? + } +} +``` diff --git a/src/doc/edition-guide/src/rust-2018/macros/custom-derive.md b/src/doc/edition-guide/src/rust-2018/macros/custom-derive.md new file mode 100644 index 0000000000..ca175bde3e --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/macros/custom-derive.md @@ -0,0 +1,49 @@ +# Custom Derive + +![Minimum Rust version: 1.15](https://img.shields.io/badge/Minimum%20Rust%20Version-1.15-brightgreen.svg) + +In Rust, 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). \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/macros/index.md b/src/doc/edition-guide/src/rust-2018/macros/index.md new file mode 100644 index 0000000000..3a37a27079 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/macros/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/macros/macro-changes.md b/src/doc/edition-guide/src/rust-2018/macros/macro-changes.md new file mode 100644 index 0000000000..c06880621d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/macros/macro-changes.md @@ -0,0 +1,271 @@ +# Macro changes + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) + +## `macro_rules!` style macros + +In Rust 2018, you can import specific macros from external crates via `use` +statements, rather than the old `#[macro_use]` attribute. + +For example, consider a `bar` crate that implements a `baz!` macro. In +`src/lib.rs`: + +```rust +#[macro_export] +macro_rules! baz { + () => () +} +``` + +In your crate, you would have written + +```rust,ignore +// Rust 2015 + +#[macro_use] +extern crate bar; + +fn main() { + baz!(); +} +``` + +Now, you write: + +```rust,ignore +// Rust 2018 + +use bar::baz; + +fn main() { + baz!(); +} +``` + +This moves `macro_rules` macros to be a bit closer to other kinds of items. + +Note that you'll still need `#[macro_use]` to use macros you've defined +in your own crate; this feature only works for importing macros from +external crates. + +## Procedural macros + +When using procedural macros to derive traits, you will have to name the macro +that provides the custom derive. This generally matches the name of the trait, +but check with the documentation of the crate providing the derives to be sure. + +For example, with Serde you would have written + +```rust,ignore +// Rust 2015 +extern crate serde; +#[macro_use] extern crate serde_derive; + +#[derive(Serialize, Deserialize)] +struct Bar; +``` + +Now, you write instead: + +```rust,ignore +// Rust 2018 +use serde_derive::{Serialize, Deserialize}; + +#[derive(Serialize, Deserialize)] +struct Bar; +``` + + +## More details + +This only works for macros defined in external crates. +For macros defined locally, `#[macro_use] mod foo;` is still required, as it was in Rust 2015. + +### Local helper macros + +Sometimes it is helpful or necessary to have helper macros inside your module. This can make +supporting both versions of rust more complicated. + +For example, let's make a simplified (and slightly contrived) version of the `log` crate in 2015 +edition style: + +```rust +use std::fmt; + +/// How important/severe the log message is. +#[derive(Copy, Clone)] +pub enum LogLevel { + Warn, + Error +} + +impl fmt::Display for LogLevel { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + LogLevel::Warn => write!(f, "warning"), + LogLevel::Error => write!(f, "error"), + } + } +} + +// A helper macro to log the message. +#[doc(hidden)] +#[macro_export] +macro_rules! __impl_log { + ($level:expr, $msg:expr) => {{ + println!("{}: {}", $level, $msg) + }} +} + +/// Warn level log message +#[macro_export] +macro_rules! warn { + ($($args:tt)*) => { + __impl_log!($crate::LogLevel::Warn, format_args!($($args)*)) + } +} + +/// Error level log message +#[macro_export] +macro_rules! error { + ($($args:tt)*) => { + __impl_log!($crate::LogLevel::Error, format_args!($($args)*)) + } +} +``` + +Our `__impl_log!` macro is private to our module, but needs to be exported as it is called by other +macros, and in 2015 edition all used macros must be exported. + +Now, in 2018 this example will not compile: + +```rust,ignore +use log::error; + +fn main() { + error!("error message"); +} +``` + +will give an error message about not finding the `__impl_log!` macro. This is because unlike in +the 2015 edition, macros are namespaced and we must import them. We could do + +```rust,ignore +use log::{__impl_log, error}; +``` + +which would make our code compile, but `__impl_log` is meant to be an implementation detail! + +#### Macros with `$crate::` prefix. + +The cleanest way to handle this situation is to use the `$crate::` prefix for macros, the same as +you would for any other path. Versions of the compiler >= 1.30 will handle this in both editions: + +```rust +macro_rules! warn { + ($($args:tt)*) => { + $crate::__impl_log!($crate::LogLevel::Warn, format_args!($($args)*)) + } +} + +// ... +``` + +However, this will not work for older versions of the compiler that don't understand the +`$crate::` prefix for macros. + +#### Macros using `local_inner_macros` + +We also have the `local_inner_macros` modifier that we can add to our `#[macro_export]` attribute. +This has the advantage of working with older rustc versions (older versions just ignore the extra +modifier). The downside is that it's a bit messier: + +```rust,ignore +#[macro_export(local_inner_macros)] +macro_rules! warn { + ($($args:tt)*) => { + __impl_log!($crate::LogLevel::Warn, format_args!($($args)*)) + } +} +``` + +So the code knows to look for any macros used locally. But wait - this won't compile, because we +use the `format_args!` macro that isn't in our local crate (hence the convoluted example). The +solution is to add a level of indirection: we create a macro that wraps `format_args`, but is local +to our crate. That way everything works in both editions (sadly we have to pollute the global +namespace a bit, but that's ok). + +```rust +// I've used the pattern `___` 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. :) diff --git a/src/doc/edition-guide/src/rust-2018/module-system/index.md b/src/doc/edition-guide/src/rust-2018/module-system/index.md new file mode 100644 index 0000000000..79a1b66a7b --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/module-system/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/module-system/more-visibility-modifiers.md b/src/doc/edition-guide/src/rust-2018/module-system/more-visibility-modifiers.md new file mode 100644 index 0000000000..cd7b7c1b65 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/module-system/more-visibility-modifiers.md @@ -0,0 +1,16 @@ +# More visibility modifiers + +![Minimum Rust version: 1.18](https://img.shields.io/badge/Minimum%20Rust%20Version-1.18-brightgreen.svg) + +You can use the `pub` keyword to make something a part of a module's public interface. But in +addition, there are some new forms: + +```rust,ignore +pub(crate) struct Foo; + +pub(in a::b::c) struct Bar; +``` + +The first form makes the `Foo` struct public to your entire crate, but not +externally. The second form is similar, but makes `Bar` public for one other +module, `a::b::c` in this case. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/module-system/nested-imports-with-use.md b/src/doc/edition-guide/src/rust-2018/module-system/nested-imports-with-use.md new file mode 100644 index 0000000000..b813590cde --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/module-system/nested-imports-with-use.md @@ -0,0 +1,35 @@ +# Nested imports with `use` + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) + +A new way to write `use` statements has been added to Rust: nested import +groups. If 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. diff --git a/src/doc/edition-guide/src/rust-2018/module-system/path-clarity.md b/src/doc/edition-guide/src/rust-2018/module-system/path-clarity.md new file mode 100644 index 0000000000..122c6811c3 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/module-system/path-clarity.md @@ -0,0 +1,390 @@ +# Path clarity + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for "uniform paths" + +The module system is often one of the hardest things for people new to Rust. Everyone +has their own things that take time to master, of course, but there's a root +cause for why it's so confusing to many: while there are simple and +consistent rules defining the module system, their consequences can feel +inconsistent, counterintuitive and mysterious. + +As such, the 2018 edition of Rust introduces a few new module system +features, but they end up *simplifying* the module system, to make it more +clear as to what is going on. + +Here's a brief summary: + +* `extern crate` is no longer needed in 99% of circumstances. +* The `crate` keyword refers to the current crate. +* Absolute paths begin with a crate name, where the keyword `crate` + refers to the current crate. +* A `foo.rs` and `foo/` subdirectory may coexist; `mod.rs` is no longer needed + when placing submodules in a subdirectory. + +These may seem like arbitrary new rules when put this way, but the mental +model is now significantly simplified overall. Read on for more details! + +> Additionally, in nightly, there's an additional possible tweak to paths +> called "Uniform paths". This is backwards compatible with the new path +> changes. Uniform paths have a dedicated section at the end of this guide. + +## More details + +Let's talk about each new feature in turn. + +### No more `extern crate` + +This one is quite straightforward: you no longer need to write `extern crate` to +import a crate into your project. Before: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +mod submodule { + use futures::Future; +} +``` + +After: + +```rust,ignore +// Rust 2018 + +mod submodule { + use futures::Future; +} +``` + +Now, to add a new crate to your project, you can add it to your `Cargo.toml`, +and then there is no step two. If you're not using Cargo, you already had to pass +`--extern` flags to give `rustc` the location of external crates, so you'd just +keep doing what you were doing there as well. + +> One small note here: `cargo fix` will not currently automate this change. We may +> have it do this for you in the future. + +#### An exception + +There's one exception to this rule, and that's the "sysroot" crates. These are the +crates distributed with Rust itself. We'd eventually like to remove the requirement +for `extern crate` for them as well, but it hasn't shipped yet. + +You'll need to use `extern crate` for: + +* `proc_macro` + +Additionally, you would need to use it for: + +* `core` +* `std` + +However, `extern crate std;` is already implicit, and with `#![no_std]`, +`extern crate core;` is already implicit. You'll only need these in highly +specialized situations. + +Finally, on nightly, you'll need it for crates like: + +* `alloc` +* `test` + +#### Macros + +One other use for `extern crate` was to import macros; that's no longer needed. +Check [the macro section](rust-2018/macros/macro-changes.html) for more. + +If you've been using `as` to rename your crate like this: + +```rust,ignore +extern crate futures as f; + +use f::Future; +``` + +then removing the `extern crate` line on its own won't work. You'll need to do this: + +```rust,ignore +use futures as f; + +use self::f::Future; +``` + +This change will need to happen in any module that uses `f`. + +### The `crate` keyword refers to the current crate. + +In `use` declarations and in other code, you can refer to the root of the +current crate with the `crate::` prefix. For instance, `crate::foo::bar` will +always refer to the name `bar` inside the module `foo`, from anywhere else in +the same crate. + +The prefix `::` previously referred to either the crate root or an external +crate; it now unambiguously refers to an external crate. For instance, +`::foo::bar` always refers to the name `bar` inside the external crate `foo`. + +### Changes to paths + +In Rust 2018, paths in `use` declarations *must* begin with a crate name, +`crate`, `self`, or `super`. + +Code that looked like this: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +use futures::Future; + +mod foo { + pub struct Bar; +} + +use foo::Bar; +``` + +Now looks like this: + +```rust,ignore +// Rust 2018 + +// 'futures' is the name of a crate +use futures::Future; + +mod foo { + pub struct Bar; +} + +// 'crate' means the current crate +use crate::foo::Bar; +``` + +In addition, all of these path forms are available outside of `use` +declarations as well, which eliminates many sources of confusion. Consider +this code in Rust 2015: + +```rust,ignore +// Rust 2015 + +extern crate futures; + +mod submodule { + // this works! + use futures::Future; + + // so why doesn't this work? + fn my_poll() -> futures::Poll { ... } +} + +fn main() { + // this works + let five = std::sync::Arc::new(5); +} + +mod submodule { + fn function() { + // ... so why doesn't this work + let five = std::sync::Arc::new(5); + } +} +``` + +> In real code, you couldn't repeat `mod submodule`, and `function` would be defined +> in the first `mod` block. + +In the `futures` example, the `my_poll` function signature is incorrect, +because `submodule` contains no items named `futures`; that is, this path is +considered relative. `use futures::` works even though a lone `futures::` +doesn't! With `std` it can be even more confusing, as you never wrote the +`extern crate std;` line at all. So why does it work in `main` but not in a +submodule? Same thing: it's a relative path because it's not in a `use` +declaration. `extern crate std;` is inserted at the crate root, so it's fine +in `main`, but it doesn't exist in the submodule at all. + +Let's look at how this change affects things: + +```rust,ignore +// Rust 2018 + +// no more `extern crate futures;` + +mod submodule { + // 'futures' is the name of a crate, so this works + use futures::Future; + + // 'futures' is the name of a crate, so this works + fn my_poll() -> 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. diff --git a/src/doc/edition-guide/src/rust-2018/module-system/raw-identifiers.md b/src/doc/edition-guide/src/rust-2018/module-system/raw-identifiers.md new file mode 100644 index 0000000000..ff70964b23 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/module-system/raw-identifiers.md @@ -0,0 +1,68 @@ +# Raw identifiers + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) + +Rust, like many programming languages, has the concept of "keywords". +These identifiers mean something to the language, and so you cannot use them in +places like variable names, function names, and other places. +Raw identifiers let you use keywords where they would not normally be allowed. + +For example, `match` is a keyword. If you try to compile this function: + +```rust,ignore +fn match(needle: &str, haystack: &str) -> bool { + haystack.contains(needle) +} +``` + +You'll get this error: + +```text +error: expected identifier, found keyword `match` + --> src/main.rs:4:4 + | +4 | fn match(needle: &str, haystack: &str) -> bool { + | ^^^^^ expected identifier, found keyword +``` + +You can write this with a raw identifier: + +```rust +fn r#match(needle: &str, haystack: &str) -> bool { + haystack.contains(needle) +} + +fn main() { + assert!(r#match("foo", "foobar")); +} +``` + +Note the `r#` prefix on both the function name as well as the call. + +## Motivation + +This feature is useful for a few reasons, but the primary motivation was +inter-edition situations. For example, `try` is not a keyword in the 2015 +edition, but is in the 2018 edition. So if you have a library that is written +in Rust 2015 and has a `try` function, to call it in Rust 2018, you'll need +to use the raw identifier. + +## New keywords + +The new confirmed keywords in edition 2018 are: + +### `async` and `await` + +[RFC 2394]: https://github.com/rust-lang/rfcs/blob/master/text/2394-async_await.md#final-syntax-for-the-await-expression + +Here, `async` is reserved for use in `async fn` as well as in `async ||` closures and +`async { .. }` blocks. Meanwhile, `await` is reserved to keep our options open +with respect to `await!(expr)` syntax. See [RFC 2394] for more details. + +### `try` + +[RFC 2388]: https://github.com/rust-lang/rfcs/pull/2388 + +The `do catch { .. }` blocks have been renamed to `try { .. }` and to support +that, the keyword `try` is reserved in edition 2018. +See [RFC 2388] for more details. diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/default-match-bindings.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/default-match-bindings.md new file mode 100644 index 0000000000..05107c613e --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/default-match-bindings.md @@ -0,0 +1,61 @@ +# Default match bindings + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Have you ever had a borrowed `Option` and tried to match on it? You +probably wrote this: + +```rust,ignore +let s: &Option = &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 = &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 = 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` with a `Some` variant, you are put +into `ref` mode automatically, giving you a borrowed view of the internal +data. Similarly, `&mut Option` would give you a `ref mut` view. diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/index.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/index.md new file mode 100644 index 0000000000..a8cfb0fafe --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/index.md @@ -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]. diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/inference-in-structs.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/inference-in-structs.md new file mode 100644 index 0000000000..48c4d7bf74 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/inference-in-structs.md @@ -0,0 +1,72 @@ +# `T: 'a` inference in structs + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) + +An annotation in the form of `T: 'a`, where `T` is either a type or another +lifetime, is called an *"outlives"* requirement. Note that *"outlives"* also +implies `'a: 'a`. + +One way in which edition 2018 helps you out in maintaining flow when writing +programs is by removing the need to explicitly annotate these `T: 'a` outlives +requirements in `struct` definitions. Instead, the requirements will be +inferred from the fields present in the definitions. + +Consider the following `struct` definitions in Rust 2015: + +```rust +// Rust 2015 + +struct Ref<'a, T: 'a> { + field: &'a T +} + +// or written with a `where` clause: + +struct WhereRef<'a, T> where T: 'a { + data: &'a T +} + +// with nested references: + +struct RefRef<'a, 'b: 'a, T: 'b> { + field: &'a &'b T, +} + +// using an associated type: + +struct ItemRef<'a, T: Iterator> +where + T::Item: 'a +{ + field: &'a T::Item +} +``` + +In Rust 2018, since the requirements are inferred, you can instead write: + +```rust,ignore +// Rust 2018 + +struct Ref<'a, T> { + field: &'a T +} + +struct WhereRef<'a, T> { + data: &'a T +} + +struct RefRef<'a, 'b, T> { + field: &'a &'b T, +} + +struct ItemRef<'a, T: Iterator> { + field: &'a T::Item +} +``` + +If you prefer to be more explicit in some cases, that is still possible. + +## More details + +For more details, see [the tracking issue](https://github.com/rust-lang/rust/issues/44493) +and [the RFC](https://github.com/rust-lang/rfcs/pull/2093). diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/lifetime-elision-in-impl.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/lifetime-elision-in-impl.md new file mode 100644 index 0000000000..a3a45ced15 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/lifetime-elision-in-impl.md @@ -0,0 +1,75 @@ +# Lifetime elision in impl + +![Minimum Rust version: 1.31](https://img.shields.io/badge/Minimum%20Rust%20Version-1.31-brightgreen.svg) + +When writing `impl` blocks, you can now elide lifetime annotations in some +situations. + +Consider a trait like `MyIterator`: + +```rust,ignore +trait MyIterator { + type Item; + fn next(&mut self) -> Option; +} +``` + +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).next() + } +} +``` + +Note all of the `'a` annotations. In Rust 2018, we can write this: + +```rust,ignore +impl MyIterator for &mut I { + type Item = I::Item; + fn next(&mut self) -> Option { + (*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, +} +``` + +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 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 \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.md new file mode 100644 index 0000000000..93da3fb907 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/non-lexical-lifetimes.md @@ -0,0 +1,83 @@ +# Non-lexical lifetimes + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) + +The borrow checker has been enhanced to accept more code, via a mechanism +called "non-lexical lifetimes." Consider this example: + +```rust,ignore +fn main() { + let mut x = 5; + + let y = &x; + + let z = &mut x; +} +``` + +In older Rust, this is a compile-time error: + +```text +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> src/main.rs:5:18 + | +4 | let y = &x; + | - immutable borrow occurs here +5 | let z = &mut x; + | ^ mutable borrow occurs here +6 | } + | - immutable borrow ends here +``` + +This is because lifetimes follow "lexical scope"; that is, the borrow from `y` is +considered to be held until `y` goes out of scope at the end of `main`, even though +we never use `y` again. This code is fine, but the borrow checker could not handle it. + +Today, this code will compile just fine. + +## Better errors + +What if we did use `y`, like this? + +```rust,ignore +fn main() { + let mut x = 5; + let y = &x; + let z = &mut x; + + println!("y: {}", y); +} +``` + +Here's the error: + +```text +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> src/main.rs:5:18 + | +4 | let y = &x; + | - immutable borrow occurs here +5 | let z = &mut x; + | ^ mutable borrow occurs here +... +8 | } + | - immutable borrow ends here +``` + +With non-lexical lifetimes, the error changes slightly: + +```text +error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable + --> src/main.rs:5:13 + | +4 | let y = &x; + | -- immutable borrow occurs here +5 | let z = &mut x; + | ^^^^^^ mutable borrow occurs here +6 | +7 | println!("y: {}", y); + | - borrow later used here +``` + +Instead of pointing to where `y` goes out of scope, it shows you where +the conflicting borrow occurs. This makes these sorts of errors *far* easier to debug. diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/simpler-lifetimes-in-static-and-const.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/simpler-lifetimes-in-static-and-const.md new file mode 100644 index 0000000000..113c5705aa --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/simpler-lifetimes-in-static-and-const.md @@ -0,0 +1,41 @@ +# Simpler lifetimes in `static` and `const` + +![Minimum Rust version: 1.17](https://img.shields.io/badge/Minimum%20Rust%20Version-1.17-brightgreen.svg) + +In older Rust, you had to explicitly write the `'static` lifetime in any +`static` or `const` that needed a lifetime: + +```rust +# mod foo { +const NAME: &'static str = "Ferris"; +# } +# mod bar { +static NAME: &'static str = "Ferris"; +# } +``` + +But `'static` is the only possible lifetime there. So Rust now assumes the `'static` lifetime, +and you don't have to write it out: + +```rust +# mod foo { +const NAME: &str = "Ferris"; +# } +# mod bar { +static NAME: &str = "Ferris"; +# } +``` + +In some situations, this can remove a *lot* of boilerplate: + +```rust +# mod foo { +// old +const NAMES: &'static [&'static str; 2] = &["Ferris", "Bors"]; +# } +# mod bar { + +// new +const NAMES: &[&str; 2] = &["Ferris", "Bors"]; +# } +``` diff --git a/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.md b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.md new file mode 100644 index 0000000000..88c0caf0f6 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/ownership-and-lifetimes/the-anonymous-lifetime.md @@ -0,0 +1,103 @@ +# `'_`, the anonymous lifetime + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) + +Rust 2018 allows you to explicitly mark where a lifetime is elided, for types +where this elision might otherwise be unclear. To do this, you can use the +special lifetime `'_` much like you can explicitly mark that a type is inferred +with the syntax `let x: _ = ..;`. + +Let's say, for whatever reason, that we have a simple wrapper around `&'a str`: + +```rust +struct StrWrap<'a>(&'a str); +``` + +In Rust 2015, you might have written: + +```rust +// Rust 2015 + +use std::fmt; + +# struct StrWrap<'a>(&'a str); + +fn make_wrapper(string: &str) -> StrWrap { + StrWrap(string) +} + +impl<'a> fmt::Debug for StrWrap<'a> { + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.write_str(self.0) + } +} +``` + +In Rust 2018, you can instead write: + +```rust +#![feature(rust_2018_preview)] + +# use std::fmt; +# struct StrWrap<'a>(&'a str); + +// Rust 2018 + +fn make_wrapper(string: &str) -> StrWrap<'_> { + StrWrap(string) +} + +impl fmt::Debug for StrWrap<'_> { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.write_str(self.0) + } +} +``` + +## More details + +In the Rust 2015 snippet above, we've used `-> StrWrap`. However, unless you take +a look at the definition of `StrWrap`, it is not clear that the returned value +is actually borrowing something. Therefore, starting with Rust 2018, it is +deprecated to leave off the lifetime parameters for non-reference-types (types +other than `&` and `&mut`). Instead, where you previously wrote `-> StrWrap`, +you should now write `-> StrWrap<'_>`, making clear that borrowing is occurring. + +What exactly does `'_` mean? It depends on the context! +In output contexts, as in the return type of `make_wrapper`, +it refers to a single lifetime for all "output" locations. +In input contexts, a fresh lifetime is generated for each "input location". +More concretely, to understand input contexts, consider the following example: + +```rust +// Rust 2015 + +struct Foo<'a, 'b: 'a> { + field: &'a &'b str, +} + +impl<'a, 'b: 'a> Foo<'a, 'b> { + // some methods... +} +``` + +We can rewrite this as: + +```rust +#![feature(rust_2018_preview)] + +# struct Foo<'a, 'b: 'a> { +# field: &'a &'b str, +# } + +// Rust 2018 + +impl Foo<'_, '_> { + // some methods... +} +``` + +This is the same, because for each `'_`, a fresh lifetime is generated. +Finally, the relationship `'a: 'b` which the struct requires must be upheld. + +For more details, see the [tracking issue on In-band lifetime bindings](https://github.com/rust-lang/rust/issues/44524). \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md new file mode 100644 index 0000000000..5a8a394f7d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/cdylib-crates-for-c-interoperability.md @@ -0,0 +1,18 @@ +# cdylib crates for C interoperability + +![Minimum Rust version: 1.10](https://img.shields.io/badge/Minimum%20Rust%20Version-1.10-brightgreen.svg) for `rustc` + +![Minimum Rust version: 1.11](https://img.shields.io/badge/Minimum%20Rust%20Version-1.11-brightgreen.svg) for `cargo` + +If you're producing a library that you intend to be used from C (or another +language through a C FFI), there's no need for Rust to include Rust-specific +stuff in the final object code. For libraries like that, you'll want to use +the `cdylib` crate type in your `Cargo.toml`: + +```toml +[lib] +crate-type = ["cdylib"] +``` + +This will produce a smaller binary, with no Rust-specific information inside +of it. diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/global-allocators.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/global-allocators.md new file mode 100644 index 0000000000..43f6ce8d67 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/global-allocators.md @@ -0,0 +1,35 @@ +# Global allocators + +![Minimum Rust version: 1.28](https://img.shields.io/badge/Minimum%20Rust%20Version-1.28-brightgreen.svg) + +Allocators are the way that programs in Rust obtain memory from the system at +runtime. Previously, Rust did not allow changing the way memory is obtained, +which prevented some use cases. On some platforms, this meant using jemalloc, +on others, the system allocator, but there was no way for users to control +this key component. With 1.28.0, the `#[global_allocator]` attribute is now +stable, which allows Rust programs to set their allocator to the system +allocator, as well as define new allocators by implementing the `GlobalAlloc` +trait. + +The default allocator for Rust programs on some platforms is jemalloc. The +standard library now provides a handle to the system allocator, which can be +used to switch to the system allocator when desired, by declaring a static +and marking it with the `#[global_allocator]` attribute. + +```rust +use std::alloc::System; + +#[global_allocator] +static GLOBAL: System = System; + +fn main() { + let mut v = Vec::new(); + // This will allocate memory using the system allocator. + v.push(1); +} +``` + +However, sometimes you want to define a custom allocator for a given +application domain. This is also relatively easy to do by implementing the +`GlobalAlloc` trait. You can read more about how to do this in [the +documentation](https://doc.rust-lang.org/std/alloc/trait.GlobalAlloc.html). \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/index.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/index.md new file mode 100644 index 0000000000..2efae82c41 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/libcore-for-low-level-rust.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/libcore-for-low-level-rust.md new file mode 100644 index 0000000000..fc64cba67d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/libcore-for-low-level-rust.md @@ -0,0 +1,31 @@ +# libcore for low-level Rust + +![Minimum Rust version: 1.6](https://img.shields.io/badge/Minimum%20Rust%20Version-1.6-brightgreen.svg) + +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/). diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/msvc-toolchain-support.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/msvc-toolchain-support.md new file mode 100644 index 0000000000..67549e5588 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/msvc-toolchain-support.md @@ -0,0 +1,18 @@ +# MSVC toolchain support + +![Minimum Rust version: 1.2](https://img.shields.io/badge/Minimum%20Rust%20Version-1.2-brightgreen.svg) + +At the release of Rust 1.0, we only supported the GNU toolchain on Windows. With the +release of Rust 1.2, we introduced initial support for the MSVC toolchain. After that, +as support matured, we eventually made it the default choice for Windows users. + +The difference between the two matters for interacting with C. If you're using a library +built with one toolchain or another, you need to match that with the appropriate Rust +toolchain. If you're not sure, go with MSVC; it's the default for good reason. + +To use this feature, simply use Rust on Windows, and the installer will default to it. +If you'd prefer to switch to the GNU toolchain, you can install it with Rustup: + +```console +$ rustup toolchain install stable-x86_64-pc-windows-gnu +``` \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md new file mode 100644 index 0000000000..076a271e0a --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/musl-support-for-fully-static-binaries.md @@ -0,0 +1,45 @@ +# MUSL support for fully static binaries + +![Minimum Rust version: 1.1](https://img.shields.io/badge/Minimum%20Rust%20Version-1.1-brightgreen.svg) + +By default, Rust will statically link all Rust code. However, if you use the +standard library, it will dynamically link to the system's `libc` +implementation. + +If you'd like a 100% static binary, the [`MUSL +libc`](https://www.musl-libc.org/) can be used on Linux. + +## Installing MUSL support + +To add support for MUSL, you need to choose the correct target. [The forge +has a full list of +targets](https://forge.rust-lang.org/platform-support.html) supported, +with a number of ones using `musl`. + +If you're not sure what you want, it's probably `x86_64-unknown-linux-musl`, +for 64-bit Linux. We'll be using this target in this guide, but the +instructions remain the same for other targets, just change the name wherever +we mention the target. + +To get support for this target, you use `rustup`: + +```console +$ rustup target add x86_64-unknown-linux-musl +``` + +This will install support for the default toolchain; to install for other toolchains, +add the `--toolchain` flag. For example: + +```console +$ rustup target add x86_64-unknown-linux-musl --toolchain=nightly +``` + +## Building with MUSL + +To use this new target, pass the `--target` flag to Cargo: + +```console +$ cargo build --target x86_64-unknown-linux-musl +``` + +The binary produced will now be built with MUSL! \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/platform-and-target-support/webassembly-support.md b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/webassembly-support.md new file mode 100644 index 0000000000..55a3a2805d --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/platform-and-target-support/webassembly-support.md @@ -0,0 +1,28 @@ +# WebAssembly support + +![Minimum Rust version: 1.14](https://img.shields.io/badge/Minimum%20Rust%20Version-1.14-brightgreen.svg) for `emscripten` + +![Minimum Rust version: nightly](https://img.shields.io/badge/Minimum%20Rust%20Version-nightly-red.svg) for `wasm32-unknown-unknown` + +Rust has gained support for [WebAssembly](https://webassembly.org/), meaning +that you can run Rust code in your browser, client-side. + +In Rust 1.14, we gained support through +[emscripten](http://kripken.github.io/emscripten-site/index.html). With it +installed, you can write Rust code and have it produce +[asm.js](http://asmjs.org/) (the precusor to wasm) and/or WebAssembly. + +Here's an example of using this support: + +```console +$ rustup target add wasm32-unknown-emscripten +$ echo 'fn main() { println!("Hello, Emscripten!"); }' > hello.rs +$ rustc --target=wasm32-unknown-emscripten hello.rs +$ node hello.js +``` + +However, in the meantime, Rust has also grown its own support, independent +from Emscripten. This is known as "the unknown target", because instead of +`wasm32-unknown-emscripten`, it's `wasm32-unknown-unknown`. This will be +the preferred target to use once it's ready, but for now, it's really +only well-supported in nightly. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/rustdoc/documentation-tests-can-now-compile-fail.md b/src/doc/edition-guide/src/rust-2018/rustdoc/documentation-tests-can-now-compile-fail.md new file mode 100644 index 0000000000..35207c61bc --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/rustdoc/documentation-tests-can-now-compile-fail.md @@ -0,0 +1,19 @@ +# Documentation tests can now compile-fail + +![Minimum Rust version: 1.22](https://img.shields.io/badge/Minimum%20Rust%20Version-1.22-brightgreen.svg) + +You can now create `compile-fail` tests in Rustdoc, like this: + +``` +/// ```compile_fail +/// let x = 5; +/// x += 2; // shouldn't compile! +/// ``` +# fn foo() {} +``` + +Please note that these kinds of tests can be more fragile than others, as +additions to Rust may cause code to compile when it previously would not. +Consider the first release with `?`, for example: code using `?` would fail +to compile on Rust 1.21, but compile successfully on Rust 1.22, causing your +test suite to start failing. diff --git a/src/doc/edition-guide/src/rust-2018/rustdoc/index.md b/src/doc/edition-guide/src/rust-2018/rustdoc/index.md new file mode 100644 index 0000000000..200fb59c30 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/rustdoc/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/rustdoc/rustdoc-uses-commonmark.md b/src/doc/edition-guide/src/rust-2018/rustdoc/rustdoc-uses-commonmark.md new file mode 100644 index 0000000000..c187114988 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/rustdoc/rustdoc-uses-commonmark.md @@ -0,0 +1,16 @@ +# Rustdoc uses CommonMark + +![Minimum Rust version: 1.25](https://img.shields.io/badge/Minimum%20Rust%20Version-1.25-brightgreen.svg) for support by default + +![Minimum Rust version: 1.23](https://img.shields.io/badge/Minimum%20Rust%20Version-1.23-red.svg) for support via a flag + +Rustdoc lets you write documentation comments in Markdown. At Rust 1.0, we +were using the `hoedown` markdown implementation, written in C. Markdown is +more of a family of implementations of an idea, and so `hoedown` had its own +dialect, like many parsers. The [CommonMark project](https://commonmark.org/) +has attempted to define a more strict version of Markdown, and so now, Rustdoc +uses it by default. + +As of Rust 1.23, we still defaulted to `hoedown`, but you could enable +Commonmark via a flag, `--enable-commonmark`. Today, we only support +CommonMark. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/rustup-for-managing-rust-versions.md b/src/doc/edition-guide/src/rust-2018/rustup-for-managing-rust-versions.md new file mode 100644 index 0000000000..5b960fc8c2 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/rustup-for-managing-rust-versions.md @@ -0,0 +1,212 @@ +# Rustup for managing Rust versions + +![Minimum Rust version: various](https://img.shields.io/badge/Minimum%20Rust%20Version-various-brightgreen.svg) (this tool has its own versioning scheme and works with all Rust versions) + +The [Rustup](https://rustup.rs/) tool has become *the* recommended way to +install Rust, and is advertised on our website. Its powers go further than +that though, allowing you to manage various versions, components, and +platforms. + +## For installing Rust + +To install Rust through Rustup, you can go to +, which will let you know how to do +so on your platform. This will install both `rustup` itself and the `stable` +version of `rustc` and `cargo`. + +To install a specific Rust version, you can use `rustup install`: + +```console +$ rustup install 1.30.0 +``` + +This works for a specific nightly, as well: + +```console +$ rustup install nightly-2018-08-01 +``` + +As well as any of our release channels: + +```console +$ rustup install stable +$ rustup install beta +$ rustup install nightly +``` + +## For updating your installation + +To update all of the various channels you may have installed: + +```console +$ rustup update +``` + +This will look at everything you've installed, and if there are new releases, +will update anything that has one. + +## Managing versions + +To set the default toolchain to something other than `stable`: + +```console +$ rustup toolchain default nightly +``` + +To use a toolchain other than the default, use `rustup run`: + +```console +$ rustup run nightly cargo build +``` + +There's also an alias for this that's a little shorter: + +```console +$ cargo +nightly build +``` + +If you'd like to have a different default per-directory, that's easy too! +If you run this inside of a project: + +```console +$ rustup override set nightly +``` + +Then when you're in that directory, any invocations of `rustc` or `cargo` +will use that toolchain. To share this with others, you can create a +`rust-toolchain` file with the contents of a toolchain, and check it into +source control. Now, when someone clones your project, they'll get the +right version without needing to `override set` themselves. + +## Installing other targets + +Rust supports cross-compiling to other targets, and Rustup can help you +manage them. For example, to use MUSL: + +```console +$ rustup target add x86_64-unknown-linux-musl +``` + +And then you can + +```console +$ cargo build --target=x86_64-unknown-linux-musl +``` + +To see the full list of targets you can install: + +```console +$ rustup target list +``` + +## Installing components + +Components are used to install certain kinds of tools. While `cargo-install` +has you covered for most tools, some tools need deep integration into the +compiler. Rustup knows exactly what version of the compiler you're using, and +so it's got just the information that these tools need. + +Components are per-toolchain, so if you want them to be available to more +than one toolchain, you'll need to install them multiple times. In the +following examples, add a `--toolchain` flag, set to the toolchain you +want to install for, `nightly` for example. Without this flag, it will +install the component for the default toolchain. + +To see the full list of components you can install: + +```console +$ rustup component list +``` + +Next, let's talk about some popular components and when you might want to +install them. + +### `rust-docs`, for local documentation + +This first component is installed by default when you install a toolchain. It +contains a copy of Rust's documentation, so that you can read it offline. + +This component cannot be removed for now; if that's of interest, please +comment on [this +issue](https://github.com/rust-lang-nursery/rustup.rs/issues/998). + +### `rust-src` for a copy of Rust's source code + +The `rust-src` component can give you a local copy of Rust's source code. Why +might you need this? Well, autocompletion tools like Racer use this +information to know more about the functions you're trying to call. + +```console +$ rustup component add rust-src +``` + +### The "preview" components + +There are several components in a "preview" stage. These components currently +have `-preview` in their name, and this indicates that they're not quite 100% +ready for general consumption yet. Please try them out and give us feedback, +but know that they do not follow Rust's stability guarantees, and are still +actively changing, possibly in backwards-incompatible ways. + +#### `rustfmt-preview` for automatic code formatting + +![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg) + +If you'd like to have your code automatically formatted, you can +install this component: + +```console +$ rustup component add rustfmt-preview +``` + +This will install two tools, `rustfmt` and `cargo-fmt`, that will reformat your +code for you! For example: + +```console +$ cargo fmt +``` + +will reformat your entire Cargo project. + +#### `rls-preview` for IDE integration + +![Minimum Rust version: 1.21](https://img.shields.io/badge/Minimum%20Rust%20Version-1.21-brightgreen.svg) + +Many IDE features are built off of the [`langserver` +protocol](http://langserver.org/). To gain support for Rust with these IDEs, +you'll need to install the Rust language sever, aka the "RLS": + +```console +$ rustup component add rls-preview +``` + +Your IDE should take it from there. + +#### `clippy-preview` for more lints + +For even more lints to help you write Rust code, you can install `clippy`: + +```console +$ rustup component add clippy-preview +``` + +This will install `cargo-clippy` for you: + +```console +$ cargo clippy +``` + +For more, check out [clippy's +documentation](https://github.com/rust-lang-nursery/rust-clippy). + +#### `llvm-tools-preview` for using extra LLVM tools + +If you'd like to use the `lld` linker, or other tools like `llvm-objdump` or +`llvm-objcopy`, you can install this component: + +```console +$ rustup component add llvm-tools-preview +``` + +This is the newest component, and so doesn't have good documentation at the +moment. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md b/src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md new file mode 100644 index 0000000000..b7943eb085 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/simd-for-faster-computing.md @@ -0,0 +1,108 @@ +# SIMD for faster computing + +![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) + +The basics of [SIMD](https://en.wikipedia.org/wiki/SIMD) are now available! +SIMD stands for “single instruction, multiple data.” Consider a function like +this: + +```rust +pub fn foo(a: &[u8], b: &[u8], c: &mut [u8]) { + for ((a, b), c) in a.iter().zip(b).zip(c) { + *c = *a + *b; + } +} +``` + +Here, 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::>(); +``` + +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! diff --git a/src/doc/edition-guide/src/rust-2018/slice-patterns.md b/src/doc/edition-guide/src/rust-2018/slice-patterns.md new file mode 100644 index 0000000000..6e62e0fed0 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/slice-patterns.md @@ -0,0 +1,91 @@ +# Slice patterns + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +Have you ever tried to pattern match on the contents and structure of a slice? +Rust 2018 will let you do just that. + +For example, say we want to accept a list of names and respond to that with a +greeting. With slice patterns, we can do that easy as pie with: + +```rust +fn main() { + greet(&[]); + // output: Bummer, there's no one here :( + greet(&["Alan"]); + // output: Hey, there Alan! You seem to be alone. + greet(&["Joan", "Hugh"]); + // output: Hello, Joan and Hugh. Nice to see you are at least 2! + greet(&["John", "Peter", "Stewart"]); + // output: Hey everyone, we seem to be 3 here today. +} + +fn greet(people: &[&str]) { + match people { + [] => println!("Bummer, there's no one here :("), + [only_one] => println!("Hey, there {}! You seem to be alone.", only_one), + [first, second] => println!( + "Hello, {} and {}. Nice to see you are at least 2!", + first, second + ), + _ => println!("Hey everyone, we seem to be {} here today.", people.len()), + } +} +``` + +Now, you don't have to check the length first. + +We can also match on arrays like so: + +```rust +let arr = [1, 2, 3]; + +assert_eq!("ends with 3", match arr { + [_, _, 3] => "ends with 3", + [a, b, c] => "ends with something else", +}); +``` + +## More details + +### Exhaustive patterns + +In the first example, note in particular the `_ => ...` pattern. +Since we are matching on a slice, it could be of any length, so we need a +*"catch all pattern"* to handle it. If we forgot the `_ => ...` or +`identifier => ...` pattern, we would instead get an error saying: + +```ignore +error[E0004]: non-exhaustive patterns: `&[_, _, _]` not covered +``` + +If we added a case for a slice of size `3` we would instead get: + +```ignore +error[E0004]: non-exhaustive patterns: `&[_, _, _, _]` not covered +``` + +and so on... + +### Arrays and exact lengths + +In the second example above, since arrays in Rust are of known lengths, +we have to match on exactly three elements. +If we try to match on 2 or 4 elements,we get the errors: + +```ignore +error[E0527]: pattern requires 2 elements but array has 3 +``` + +and + +```ignore +error[E0527]: pattern requires 4 elements but array has 3 +``` + +### In the pipeline + +[the tracking issue]: https://github.com/rust-lang/rust/issues/23121 + +When it comes to slice patterns, more advanced forms are planned but +have not been stabilized yet. To learn more, follow [the tracking issue]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/the-compiler/an-attribute-for-deprecation.md b/src/doc/edition-guide/src/rust-2018/the-compiler/an-attribute-for-deprecation.md new file mode 100644 index 0000000000..d414dbaa94 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/the-compiler/an-attribute-for-deprecation.md @@ -0,0 +1,35 @@ +# An attribute for deprecation + +![Minimum Rust version: 1.9](https://img.shields.io/badge/Minimum%20Rust%20Version-1.9-brightgreen.svg) + +If you're writing a library, and you'd like to deprecate something, you can +use the `deprecated` attribute: + +```rust +#[deprecated( + since = "0.2.1", + note = "Please use the bar function instead" +)] +pub fn foo() { + // ... +} +``` + +This will give your users a warning if they use the deprecated functionality: + +```text + Compiling playground v0.0.1 (file:///playground) +warning: use of deprecated item 'foo': Please use the bar function instead + --> src/main.rs:10:5 + | +10 | foo(); + | ^^^ + | + = note: #[warn(deprecated)] on by default + +``` + +Both `since` and `note` are optional. + +`since` can be in the future; you can put whatever you'd like, and what's put in +there isn't checked. diff --git a/src/doc/edition-guide/src/rust-2018/the-compiler/improved-error-messages.md b/src/doc/edition-guide/src/rust-2018/the-compiler/improved-error-messages.md new file mode 100644 index 0000000000..3b3b6896ae --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/the-compiler/improved-error-messages.md @@ -0,0 +1,49 @@ +# Improved error messages + +![Minimum Rust version: 1.12](https://img.shields.io/badge/Minimum%20Rust%20Version-1.12-brightgreen.svg) + +We're always working on error improvements, and there are little improvements +in almost every Rust version, but in Rust 1.12, a significant overhaul of the +error message system was created. + +For example, here's some code that produces an error: + +```rust,ignore +fn main() { + let mut x = 5; + + let y = &x; + + x += 1; +} +``` + +Here's the error in Rust 1.11: + +```text +foo.rs:6:5: 6:11 error: cannot assign to `x` because it is borrowed [E0506] +foo.rs:6 x += 1; + ^~~~~~ +foo.rs:4:14: 4:15 note: borrow of `x` occurs here +foo.rs:4 let y = &x; + ^ +foo.rs:6:5: 6:11 help: run `rustc --explain E0506` to see a detailed explanation +``` + +Here's the error in Rust 1.28: + +```text +error[E0506]: cannot assign to `x` because it is borrowed + --> foo.rs:6:5 + | +4 | let y = &x; + | - borrow of `x` occurs here +5 | +6 | x += 1; + | ^^^^^^ assignment to borrowed `x` occurs here + +error: aborting due to previous error +``` + +This error isn't terribly different, but shows off how the format has changed. It shows +off your code in context, rather than just showing the text of the lines themselves. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/the-compiler/incremental-compilation-for-faster-compiles.md b/src/doc/edition-guide/src/rust-2018/the-compiler/incremental-compilation-for-faster-compiles.md new file mode 100644 index 0000000000..6e7ebf8a1c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/the-compiler/incremental-compilation-for-faster-compiles.md @@ -0,0 +1,23 @@ +# Incremental Compilation + +![Minimum Rust version: 1.24](https://img.shields.io/badge/Minimum%20Rust%20Version-1.24-brightgreen.svg) + +Back in September of 2016, we [blogged about Incremental +Compilation](https://blog.rust-lang.org/2016/09/08/incremental.html). While +that post goes into the details, the idea is basically this: when 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/the-compiler/index.md b/src/doc/edition-guide/src/rust-2018/the-compiler/index.md new file mode 100644 index 0000000000..fe9b81688c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/the-compiler/index.md @@ -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]. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/trait-system/associated-constants.md b/src/doc/edition-guide/src/rust-2018/trait-system/associated-constants.md new file mode 100644 index 0000000000..26564943c2 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/trait-system/associated-constants.md @@ -0,0 +1,117 @@ +# Associated constants + +![Minimum Rust version: 1.20](https://img.shields.io/badge/Minimum%20Rust%20Version-1.20-brightgreen.svg) + +You can define traits, structs, and enums that have “associated functions”: + +```rust +struct Struct; + +impl Struct { + fn foo() { + println!("foo is an associated function of Struct"); + } +} + +fn main() { + Struct::foo(); +} +``` + +These are called “associated functions” because they are functions that are +associated with the type, that is, 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. diff --git a/src/doc/edition-guide/src/rust-2018/trait-system/dyn-trait-for-trait-objects.md b/src/doc/edition-guide/src/rust-2018/trait-system/dyn-trait-for-trait-objects.md new file mode 100644 index 0000000000..c76f0c5505 --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/trait-system/dyn-trait-for-trait-objects.md @@ -0,0 +1,42 @@ +# `dyn Trait` for trait objects + +![Minimum Rust version: 1.27](https://img.shields.io/badge/Minimum%20Rust%20Version-1.27-brightgreen.svg) + +The `dyn Trait` feature is the new syntax for using trait objects. In short: + +* `Box` becomes `Box` +* `&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 { +# unimplemented!() +} + +// new +fn function2() -> Box { +# 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. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.md b/src/doc/edition-guide/src/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.md new file mode 100644 index 0000000000..190b04e57f --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/trait-system/impl-trait-for-returning-complex-types-with-ease.md @@ -0,0 +1,168 @@ +# `impl Trait` for returning complex types with ease + +![Minimum Rust version: 1.26](https://img.shields.io/badge/Minimum%20Rust%20Version-1.26-brightgreen.svg) + +`impl Trait` is the new way to specify unnamed but concrete types that +implement a specific trait. There are two places you can put it: argument +position, and return position. + +```rust,ignore +trait Trait {} + +// argument position +fn foo(arg: impl Trait) { +} + +// return position +fn foo() -> impl Trait { +} +``` + +## Argument Position + +In argument position, this feature is quite simple. These two forms are +almost the same: + +```rust,ignore +trait Trait {} + +fn foo(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::(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 { + Box::new(5) +} +``` + +However, this has some overhead: the `Box` 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`. 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`, 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 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(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 { +``` + +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(&self) -> Result::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`, one of Rust's reference-counted types: + +```rust +use std::rc::Rc; + +trait Foo {} + +impl Foo for i32 { + +} + +fn main() { + let obj: Rc = 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` with `Rc`. \ No newline at end of file diff --git a/src/doc/edition-guide/src/rust-2018/trait-system/no-anon-params.md b/src/doc/edition-guide/src/rust-2018/trait-system/no-anon-params.md new file mode 100644 index 0000000000..94b039633c --- /dev/null +++ b/src/doc/edition-guide/src/rust-2018/trait-system/no-anon-params.md @@ -0,0 +1,23 @@ +# No more anonymous trait parameters + +![Minimum Rust version: beta](https://img.shields.io/badge/Minimum%20Rust%20Version-beta-orange.svg) + +In accordance with RFC [#1685](https://github.com/rust-lang/rfcs/pull/1685), +parameters in trait method declarations are no longer allowed to be anonymous. + +For example, in the 2015 edition, this was allowed: + +```rust +trait Foo { + fn foo(&self, u8); +} +``` + +In the 2018 edition, all parameters must be given an argument name (even if it's just +`_`): + +```rust +trait Foo { + fn foo(&self, baz: u8); +} +``` diff --git a/src/doc/nomicon/src/README.md b/src/doc/nomicon/src/README.md index f1efd919fc..6556a4d83f 100644 --- a/src/doc/nomicon/src/README.md +++ b/src/doc/nomicon/src/README.md @@ -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 diff --git a/src/doc/nomicon/src/data.md b/src/doc/nomicon/src/data.md index bf202ada08..2080b957d4 100644 --- a/src/doc/nomicon/src/data.md +++ b/src/doc/nomicon/src/data.md @@ -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 diff --git a/src/doc/nomicon/src/drop-flags.md b/src/doc/nomicon/src/drop-flags.md index e69264f281..65fff15dfc 100644 --- a/src/doc/nomicon/src/drop-flags.md +++ b/src/doc/nomicon/src/drop-flags.md @@ -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 diff --git a/src/doc/nomicon/src/exotic-sizes.md b/src/doc/nomicon/src/exotic-sizes.md index 2a9d2766ab..8ca7117e02 100644 --- a/src/doc/nomicon/src/exotic-sizes.md +++ b/src/doc/nomicon/src/exotic-sizes.md @@ -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 { + 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`, it is common to implement a `Set` as just a thin wrapper around `Map`. 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`. 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::()` +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 diff --git a/src/doc/nomicon/src/other-reprs.md b/src/doc/nomicon/src/other-reprs.md index 493e0472b7..363c888e4e 100644 --- a/src/doc/nomicon/src/other-reprs.md +++ b/src/doc/nomicon/src/other-reprs.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` 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 diff --git a/src/doc/nomicon/src/phantom-data.md b/src/doc/nomicon/src/phantom-data.md index 031e0bd0b9..c13e3f8c96 100644 --- a/src/doc/nomicon/src/phantom-data.md +++ b/src/doc/nomicon/src/phantom-data.md @@ -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 { 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 { diff --git a/src/doc/nomicon/src/repr-rust.md b/src/doc/nomicon/src/repr-rust.md index e3fd561c97..584a9a06bf 100644 --- a/src/doc/nomicon/src/repr-rust.md +++ b/src/doc/nomicon/src/repr-rust.md @@ -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 { } ``` -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::>() == -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::>() == size_of::<&T>()`. There are many types in Rust that are, or contain, non-nullable pointers such as `Box`, `Vec`, `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 diff --git a/src/doc/nomicon/src/subtyping.md b/src/doc/nomicon/src/subtyping.md index b5ce948a37..0e33658181 100644 --- a/src/doc/nomicon/src/subtyping.md +++ b/src/doc/nomicon/src/subtyping.md @@ -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`. `&` 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` 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` is a subtype of `F` (subtyping "passes through") -* F is *contravariant* over `T` if `T` being a subtype of `U` implies - `F` is a subtype of `F` (subtyping is "inverted") -* F is *invariant* over `T` otherwise (no subtyping relation can be derived) +* `F` is *covariant* if `F` is a subtype of `F` (subtyping "passes through") +* `F` is *contravariant* if `F` is a subtype of `F` (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` 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`, `Cell`, `RefCell`, `Mutex` 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` | | covariant | | +| | `Vec` | | covariant | | +| * | `UnsafeCell` | | invariant | | +| | `Cell` | | 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`) -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(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(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(input: &mut T, val: T) { + *input = val; } ``` -If mutation is by-reference, then our container is passed as `&mut Vec`. But -`&mut` is invariant over its value, so `&mut Vec` is actually invariant over `T`. -So the fact that `Vec` 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 = ..; +let spike: Box = ..; + +let mut pet: Box; +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 } ``` + diff --git a/src/librustc_codegen_llvm/mir/operand.rs b/src/librustc_codegen_llvm/mir/operand.rs index ab43531240..6b61abd15a 100644 --- a/src/librustc_codegen_llvm/mir/operand.rs +++ b/src/librustc_codegen_llvm/mir/operand.rs @@ -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); } } } diff --git a/src/librustc_codegen_llvm/mir/place.rs b/src/librustc_codegen_llvm/mir/place.rs index 062f717468..3a1aaa8595 100644 --- a/src/librustc_codegen_llvm/mir/place.rs +++ b/src/librustc_codegen_llvm/mir/place.rs @@ -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) }; diff --git a/src/librustc_driver/driver.rs b/src/librustc_driver/driver.rs index 7ad012409b..07803d0659 100644 --- a/src/librustc_driver/driver.rs +++ b/src/librustc_driver/driver.rs @@ -91,7 +91,7 @@ pub fn spawn_thread_pool 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)) diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 276b7290c2..9a0d461444 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -1460,6 +1460,11 @@ fn parse_crate_attrs<'a>(sess: &'a Session, input: &Input) -> PResult<'a, Vec(name: String, f: F) -> Result 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 diff --git a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs index 50fd4afcd7..82e0b3495d 100644 --- a/src/librustc_mir/borrow_check/nll/region_infer/mod.rs +++ b/src/librustc_mir/borrow_check/nll/region_infer/mod.rs @@ -1196,7 +1196,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { blame_span: blame_span_category.1, category: blame_span_category.0, }); - return; + continue; } } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 70324f6a14..b5290bc82b 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -3952,7 +3952,7 @@ impl<'a, 'crateloader: 'a> Resolver<'a, 'crateloader> { let first_name = match path.get(0) { // In the 2018 edition this lint is a hard error, so nothing to do - Some(seg) if seg.ident.span.rust_2015() => seg.ident.name, + Some(seg) if seg.ident.span.rust_2015() && self.session.rust_2015() => seg.ident.name, _ => return, }; diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index 88551f6566..1aa40e3b6c 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -173,7 +173,9 @@ impl<'a, 'crateloader> Resolver<'a, 'crateloader> { } ModuleOrUniformRoot::ExternPrelude => { assert!(!restricted_shadowing); - return if let Some(binding) = self.extern_prelude_get(ident, !record_used) { + return if ns != TypeNS { + Err((Determined, Weak::No)) + } else if let Some(binding) = self.extern_prelude_get(ident, !record_used) { Ok(binding) } else if !self.graph_root.unresolved_invocations.borrow().is_empty() { // Macro-expanded `extern crate` items can add names to extern prelude. diff --git a/src/librustc_typeck/check/wfcheck.rs b/src/librustc_typeck/check/wfcheck.rs index 9990d2ee2b..75207f18ab 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/src/librustc_typeck/check/wfcheck.rs @@ -343,8 +343,8 @@ fn check_item_fn<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item: &hir::Item) { fn check_item_type<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, item_id: ast::NodeId, ty_span: Span) { debug!("check_item_type: {:?}", item_id); - for_id(tcx, item_id, ty_span).with_fcx(|fcx, _this| { - let ty = fcx.tcx.type_of(fcx.tcx.hir.local_def_id(item_id)); + for_id(tcx, item_id, ty_span).with_fcx(|fcx, gcx| { + let ty = gcx.type_of(gcx.hir.local_def_id(item_id)); let item_ty = fcx.normalize_associated_types_in(ty_span, &ty); fcx.register_wf_obligation(item_ty, ty_span, ObligationCauseCode::MiscObligation); diff --git a/src/test/codegen/issue-56267-2.rs b/src/test/codegen/issue-56267-2.rs new file mode 100644 index 0000000000..53b83f4a53 --- /dev/null +++ b/src/test/codegen/issue-56267-2.rs @@ -0,0 +1,18 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] + +#[allow(dead_code)] +pub struct Foo { + foo: u64, + bar: T, +} + +// The load from bar.1 should have alignment 4. Not checking +// other loads here, as the alignment will be platform-dependent. + +// CHECK: %{{.+}} = load i32, i32* %{{.+}}, align 4 +#[no_mangle] +pub fn test(x: Foo<(i32, i32)>) -> (i32, i32) { + x.bar +} diff --git a/src/test/codegen/issue-56267.rs b/src/test/codegen/issue-56267.rs new file mode 100644 index 0000000000..2c33f55893 --- /dev/null +++ b/src/test/codegen/issue-56267.rs @@ -0,0 +1,18 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type="rlib"] + +#[allow(dead_code)] +pub struct Foo { + foo: u64, + bar: T, +} + +// The store writing to bar.1 should have alignment 4. Not checking +// other stores here, as the alignment will be platform-dependent. + +// CHECK: store i32 [[TMP1:%.+]], i32* [[TMP2:%.+]], align 4 +#[no_mangle] +pub fn test(x: (i32, i32)) -> Foo<(i32, i32)> { + Foo { foo: 0, bar: x } +} diff --git a/src/test/ui/imports/issue-56263.rs b/src/test/ui/imports/issue-56263.rs new file mode 100644 index 0000000000..4113d4390c --- /dev/null +++ b/src/test/ui/imports/issue-56263.rs @@ -0,0 +1,8 @@ +// compile-pass +// edition:2018 + +use ::std; + +fn main() { + let std = 10; +} diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs new file mode 100644 index 0000000000..dbc659b4ae --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.rs @@ -0,0 +1,25 @@ +// Test that we propagate *all* requirements to the caller, not just the first +// one. + +#![feature(nll)] + +fn once U>(f: F, s: S, t: T) -> U { + f(s, t) +} + +pub fn dangle() -> &'static [i32] { + let other_local_arr = [0, 2, 4]; + let local_arr = other_local_arr; + let mut out: &mut &'static [i32] = &mut (&[1] as _); + once(|mut z: &[i32], mut out_val: &mut &[i32]| { + // We unfortunately point to the first use in the closure in the error + // message + z = &local_arr; //~ ERROR + *out_val = &local_arr; + }, &[] as &[_], &mut *out); + *out +} + +fn main() { + println!("{:?}", dangle()); +} diff --git a/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr new file mode 100644 index 0000000000..2ad4577869 --- /dev/null +++ b/src/test/ui/nll/closure-requirements/propagate-multiple-requirements.stderr @@ -0,0 +1,17 @@ +error[E0597]: `local_arr` does not live long enough + --> $DIR/propagate-multiple-requirements.rs:17:14 + | +LL | let mut out: &mut &'static [i32] = &mut (&[1] as _); + | ------------------- type annotation requires that `local_arr` is borrowed for `'static` +LL | once(|mut z: &[i32], mut out_val: &mut &[i32]| { + | ----------------------------------------- value captured here +... +LL | z = &local_arr; //~ ERROR + | ^^^^^^^^^ borrowed value does not live long enough +... +LL | } + | - `local_arr` dropped here while still borrowed + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0597`. diff --git a/src/test/ui/rust-2018/auxiliary/edition-lint-paths.rs b/src/test/ui/rust-2018/auxiliary/edition-lint-paths.rs index cc17a9bd66..dc4ab2131a 100644 --- a/src/test/ui/rust-2018/auxiliary/edition-lint-paths.rs +++ b/src/test/ui/rust-2018/auxiliary/edition-lint-paths.rs @@ -9,3 +9,14 @@ // except according to those terms. pub fn foo() {} + +#[macro_export] +macro_rules! macro_2015 { + () => { + use edition_lint_paths as other_name; + use edition_lint_paths::foo as other_foo; + fn check_macro_2015() { + ::edition_lint_paths::foo(); + } + } +} diff --git a/src/test/ui/rust-2018/edition-lint-paths-2018.rs b/src/test/ui/rust-2018/edition-lint-paths-2018.rs new file mode 100644 index 0000000000..09b31beb77 --- /dev/null +++ b/src/test/ui/rust-2018/edition-lint-paths-2018.rs @@ -0,0 +1,10 @@ +// compile-pass +// edition:2018 +// compile-flags:--extern edition_lint_paths +// aux-build:edition-lint-paths.rs + +#![deny(absolute_paths_not_starting_with_crate)] + +edition_lint_paths::macro_2015!(); // OK + +fn main() {} diff --git a/version b/version index 9a99dfcf72..d1a9221c4b 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.31.0-beta.19 (42053f9f0 2018-11-26) \ No newline at end of file +1.31.0 (abe02cefd 2018-12-04) \ No newline at end of file