diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4456c3c..0dfd2da 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,9 +1,13 @@ name: CI -on: [push, pull_request] +on: + pull_request: + merge_group: + +env: + MDBOOK_VERSION: 0.4.40 jobs: - test: - name: Test + code-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@master @@ -12,12 +16,12 @@ jobs: - name: Install Rust run: | rustup set profile minimal - rustup toolchain install nightly -c rust-docs + rustup toolchain install nightly rustup default nightly - name: Install mdbook run: | mkdir bin - curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.14/mdbook-v0.4.14-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin echo "$(pwd)/bin" >> $GITHUB_PATH - name: Report versions run: | @@ -26,10 +30,88 @@ jobs: mdbook --version - name: Run tests run: mdbook test + + style-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Update rustup + run: rustup self update + - name: Install Rust + run: | + rustup set profile minimal + rustup toolchain install nightly -c rust-docs,rustfmt + rustup default nightly + - name: Install mdbook + run: | + mkdir bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + echo "$(pwd)/bin" >> $GITHUB_PATH + - name: Report versions + run: | + rustup --version + rustc -Vv + mdbook --version + - name: Verify the book builds + env: + SPEC_DENY_WARNINGS: 1 + run: mdbook build - name: Style checks - run: (cd style-check && cargo run -- ../src) + working-directory: style-check + run: cargo run --locked -- ../src + - name: Style fmt + working-directory: style-check + run: cargo fmt --check - name: Check for broken links run: | curl -sSLo linkcheck.sh \ https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh sh linkcheck.sh --all reference + + mdbook-spec: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Update rustup + run: rustup self update + - name: Install Rust + run: | + rustup set profile minimal + rustup toolchain install nightly -c rustfmt + rustup default nightly + - name: Install mdbook + run: | + mkdir bin + curl -sSL https://github.com/rust-lang/mdBook/releases/download/v${MDBOOK_VERSION}/mdbook-v${MDBOOK_VERSION}-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=bin + echo "$(pwd)/bin" >> $GITHUB_PATH + - name: Report versions + run: | + rustup --version + rustc -Vv + - name: Verify mdbook-spec lockfile is current + working-directory: ./mdbook-spec + run: cargo update -p mdbook-spec --locked + - name: Test mdbook-spec + working-directory: ./mdbook-spec + run: cargo test + - name: Rustfmt check + working-directory: ./mdbook-spec + run: cargo fmt --check + + # The success job is here to consolidate the total success/failure state of + # all other jobs. This job is then included in the GitHub branch protection + # rule which prevents merges unless all other jobs are passing. This makes + # it easier to manage the list of jobs via this yml file and to prevent + # accidentally adding new jobs without also updating the branch protections. + success: + name: Success gate + if: always() + needs: + - code-tests + - style-tests + - mdbook-spec + runs-on: ubuntu-latest + steps: + - run: jq --exit-status 'all(.result == "success")' <<< '${{ toJson(needs) }}' + - name: Done + run: exit 0 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8cf73c1..4877903 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,10 +14,10 @@ for the Reference. As such, we have the warning saying there's work that needs to be done. Eventually, we plan to make sure everything is well documented enough that we can remove the warning. -It is encouraged for you to read the [introduction] to familiarize yourself -with the kind of content the reference is expected to contain and the -conventions it uses. Also, the [style guide] provides more detailed guidelines -for formatting and content. +It is encouraged for you to read the [introduction] to familiarize yourself with +the kind of content the reference is expected to contain and the conventions it +uses. Also, the [Authoring Guide] provides more detailed guidelines for +formatting and content. ## Critiquing the Reference @@ -68,9 +68,9 @@ This should include links to any relevant information, such as the stabilization PR, the RFC, the tracking issue, and anything else that would be helpful for writing the documentation. +[Authoring Guide]: docs/authoring.md [introduction]: src/introduction.md [issue tracker]: https://github.com/rust-lang/reference/issues [playpen]: https://play.rust-lang.org/ [rust-lang/rust]: https://github.com/rust-lang/rust/ -[style guide]: STYLE.md [unstable]: https://doc.rust-lang.org/nightly/unstable-book/ diff --git a/README.md b/README.md index 65030a3..009a3d8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # The Rust Language Reference -This document is the primary reference for the Rust programming language. +This document is the primary reference for the Rust programming +language. This document is not normative. It may include details that are specific to `rustc` itself, and should not be taken as a specification for the @@ -9,52 +10,64 @@ what we have for now. ## Dependencies -- rustc (the Rust compiler). -- [mdbook](https://rust-lang.github.io/mdBook/) (use `cargo install mdbook` to install it). -- rust nightly (you would be required to set your Rust version to the nightly version to make sure all tests pass) +- Nightly Rust +- [mdbook](https://rust-lang.github.io/mdBook/) -## Build steps +## Installing dependencies -To build the project, follow the steps given below : +First, ensure that you have a recent copy of the nightly Rust compiler +installed, as this is needed in order to run the tests: -Clone the project by downloading the ZIP from the [GitHub page](https://github.com/rust-lang/reference) or -run the following command: - -``` -git clone https://github.com/rust-lang/reference +```sh +rustup toolchain install nightly ``` -Change the directory to the downloaded repository: +Now, ensure you have `mdbook` installed, as this is needed in order to +build the Reference: ```sh -cd reference +cargo install --locked mdbook ``` -To run the tests, you would need to set the Rust version to the nightly release. You can do this by executing the following command: +## Building -```shell -rustup override set nightly +To build the Reference, first clone the project: + +```sh +git clone https://github.com/rust-lang/reference.git ``` -This will set the nightly version only for your the current project. +(Alternatively, if you don't want to use `git`, [download][] a ZIP file +of the project, extract it using your preferred tool, and rename the +top-level directory to `reference`.) + +[download]: https://github.com/rust-lang/reference/archive/refs/heads/master.zip -If you wish to set Rust nightly for all your projects, you can run the command: +Now change your current directory to the working directory: -```shell -rustup default nightly +```sh +cd reference ``` -Now, run the following command to test the code snippets to catch compilation errors: +To test all of the code examples in the Reference, run: -```shell +```sh mdbook test ``` +For authors, consider using the server functionality which supports automatic reload. -To generate a local instance of the book, run: +To build the Reference locally (in `build/`) and open it in a web +browser, run: ```sh -mdbook build +mdbook build --open ``` -The generated HTML will be in the `book` folder. +This will open a browser with a websocket live-link to automatically reload whenever the source is updated. + +You can also open any current build of the reference by running: + +```sh +mdbook serve --open +``` diff --git a/STYLE.md b/STYLE.md index f51cba3..5a64884 100644 --- a/STYLE.md +++ b/STYLE.md @@ -1,71 +1,5 @@ # Rust reference style guide -Some conventions and content guidelines are specified in the [introduction]. -This document serves as a guide for editors and reviewers. +See the [Authoring Guide] for details on the style used in the reference. -There is a [`style-check`](style-check/) tool which is run in CI to check some of these. To use it locally, run `cargo run --manifest-path=style-check/Cargo.toml src`. - -## Markdown formatting - -* Use ATX-style heading with sentence case. -* Use one line per sentence to make diffs nicer. - Do not wrap long lines. -* Use reference links, with shortcuts if appropriate. - Place the sorted link reference definitions at the bottom of the file, or at the bottom of a section if there is an unusually large number of links that are specific to the section. - - ``` - Example of shortcut link: [enumerations] - Example of reference link with label: [block expression][block] - - [block]: expressions/block-expr.md - [enumerations]: types/enum.md - ``` - -* Links should be relative with the `.md` extension. - Links to other rust-lang books that are published with the reference or the standard library API should also be relative so that the linkchecker can validate them. -* See the [Conventions] section for formatting callouts such as notes, edition differences, and warnings. -* Formatting to avoid: - * Avoid trailing spaces. - * Avoid double blank lines. - -### Code examples - -Code examples should use code blocks with triple backticks. -The language should always be specified (such as `rust`). - -```rust -println!("Hello!"); -``` - -See https://highlightjs.org/ for a list of supported languages. - -Rust examples are tested via rustdoc, and should include the appropriate annotations when tests are expected to fail: - -* `edition2015` or `edition2018` — If it is edition-specific (see `book.toml` for the default). -* `no_run` — The example should compile successfully, but should not be executed. -* `should_panic` — The example should compile and run, but produce a panic. -* `compile_fail` — The example is expected to fail to compile. -* `ignore` — The example shouldn't be built or tested. - This should be avoided if possible. - Usually this is only necessary when the testing framework does not support it (such as external crates or modules, or a proc-macro), or it contains pseudo-code which is not valid Rust. - An HTML comment such as `` should be placed before the example to explain why it is ignored. - -See the [rustdoc documentation] for more detail. - -## Language and grammar - -* Use American English spelling. -* Use Oxford commas. -* Idioms and styling to avoid: - * Avoid slashes for alternatives ("program/binary"), use conjunctions or rewrite it ("program or binary"). - * Avoid qualifying something as "in Rust", the entire reference is about Rust. - -## Content - -* Whenever there is a difference between editions, the differences should be called out with an "Edition Differences" block. - The main text should stick to what is common between the editions. - However, for large differences (such as "async"), the main text may contain edition-specific content as long as it is made clear which editions it applies to. - -[conventions]: src/introduction.md#conventions -[introduction]: src/introduction.md -[rustdoc documentation]: https://doc.rust-lang.org/rustdoc/documentation-tests.html +[Authoring Guide]: docs/authoring.md diff --git a/book.toml b/book.toml index 2bc218f..77b8b88 100644 --- a/book.toml +++ b/book.toml @@ -6,9 +6,19 @@ author = "The Rust Project Developers" [output.html] additional-css = ["theme/reference.css"] git-repository-url = "https://github.com/rust-lang/reference/" +edit-url-template = "https://github.com/rust-lang/reference/edit/master/{path}" +smart-punctuation = true [output.html.redirect] "/expressions/enum-variant-expr.html" = "struct-expr.html" +"/unsafe-blocks.html" = "unsafe-keyword.html" +"/unsafe-functions.html" = "unsafe-keyword.html" [rust] edition = "2021" + +[preprocessor.spec] +command = "cargo run --manifest-path mdbook-spec/Cargo.toml" + +[build] +extra-watch-dirs = ["mdbook-spec/src"] diff --git a/docs/authoring.md b/docs/authoring.md new file mode 100644 index 0000000..256cb30 --- /dev/null +++ b/docs/authoring.md @@ -0,0 +1,148 @@ +# Authoring Guide + +This document serves as a guide for editors and reviewers. Some conventions and content guidelines are specified in the [introduction]. + +[introduction]: ../src/introduction.md + +## Markdown formatting + +* Use [ATX-style headings][atx] (not Setext) with [sentence case]. +* Do not use tabs, only spaces. +* Files must end with a newline. +* Lines must not end with spaces. Double spaces have semantic meaning, but can be invisible. Use a trailing backslash if you need a hard line break. +* If possible, avoid double blank lines. +* Do not use indented code blocks; use 3+ backticks code blocks instead. +* Code blocks should have an explicit language tag. +* Do not wrap long lines. This helps with reviewing diffs of the source. +* Use [smart punctuation] instead of Unicode characters. For example, use `---` for em-dash instead of the Unicode character. Characters like em-dash can be difficult to see in a fixed-width editor, and some editors may not have easy methods to enter such characters. +* Links should be relative with the `.md` extension. Links to other rust-lang books that are published with the reference or the standard library API should also be relative so that the linkchecker can validate them. +* The use of reference links is preferred, with shortcuts if appropriate. Place the sorted link reference definitions at the bottom of the file, or at the bottom of a section if there are an unusually large number of links that are specific to the section. + + ```markdown + Example of shortcut link: [enumerations] + Example of reference link with label: [block expression][block] + + [block]: expressions/block-expr.md + [enumerations]: types/enum.md + ``` +* See the [Conventions] section for formatting callouts such as notes, edition differences, and warnings. + +There are automated checks for some of these rules. Run `cargo run --manifest-path style-check/Cargo.toml -- src` to run them locally. + +[atx]: https://spec.commonmark.org/0.31.2/#atx-headings +[conventions]: ../src/introduction.md#conventions +[sentence case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case +[smart punctuation]: https://rust-lang.github.io/mdBook/format/markdown.html#smart-punctuation + +### Code examples + +Code examples should use code blocks with triple backticks. The language should always be specified (such as `rust`). + +```rust +println!("Hello!"); +``` + +See for a list of supported languages. + +Rust examples are tested via rustdoc, and should include the appropriate annotations: + +* `edition2015` or `edition2018` --- If it is edition-specific (see `book.toml` for the default). +* `no_run` --- The example should compile successfully, but should not be executed. +* `should_panic` --- The example should compile and run, but produce a panic. +* `compile_fail` --- The example is expected to fail to compile. +* `ignore` --- The example shouldn't be built or tested. This should be avoided if possible. Usually this is only necessary when the testing framework does not support it (such as external crates or modules, or a proc-macro), or it contains pseudo-code which is not valid Rust. An HTML comment such as `` should be placed before the example to explain why it is ignored. +* `Exxxx` --- If the example is expected to fail to compile with a specific error code, include that code so that rustdoc will check that the expected code is used. + +See the [rustdoc documentation] for more detail. + +[rustdoc documentation]: https://doc.rust-lang.org/rustdoc/documentation-tests.html + +## Special markdown constructs + +The following are extensions provided by [`mdbook-spec`](https://github.com/rust-lang/spec/tree/main/mdbook-spec). + +### Rules + +Most clauses should be preceded with a rule. Rules can be specified in the markdown source with the following on a line by itself: + +```markdown +r[foo.bar] +``` + +The rule name should be lowercase, with periods separating from most general to most specific (like `r[array.repeat.zero]`). + +Rules can be linked to by their ID using markdown such as `[foo.bar]`. There are automatic link references so that any rule can be referred to from any page in the book. + +In the HTML, the rules are clickable just like headers. + +### Standard library links + +You should link to the standard library without specifying a URL in a fashion similar to [rustdoc intra-doc links][intra]. Some examples: + +We can link to the page on `Option`: + +```markdown +[`std::option::Option`] +``` + +In these links, generics are ignored and can be included: + +```markdown +[`std::option::Option`] +``` + +If we don't want the full path in the text, we can write: + +```markdown +[`Option`](std::option::Option) +``` + +Macros can end in `!`. This can be helpful for disambiguation. For example, this refers to the macro rather than the module: + +```markdown +[`alloc::vec!`] +``` + +Explicit namespace disambiguation is also supported: + +```markdown +[`std::vec`](mod@std::vec) +``` + +[intra]: https://doc.rust-lang.org/rustdoc/write-documentation/linking-to-items-by-name.html + +### Admonitions + +Admonitions use a style similar to GitHub-flavored markdown, where the style name is placed at the beginning of a blockquote, such as: + +```markdown +> [!WARNING] +> This is a warning. +``` + +All this does is apply a CSS class to the blockquote. You should define the color or style of the rule in the `css/custom.css` file if it isn't already defined. + +## Style + +Idioms and styling to avoid: + +* Use American English spelling. +* Use Oxford commas. +* Avoid slashes for alternatives ("program/binary"); use conjunctions or rewrite it ("program or binary"). +* Avoid qualifying something as "in Rust"; the entire reference is about Rust. + +## Content guidelines + +The following are guidelines for the content of the reference. + +### Targets + +The reference does not document which targets exist, or the properties of specific targets. The reference may refer to *platforms* or *target properties* where required by the language. Some examples: + +* Conditional-compilation keys like `target_os` are specified to exist, but not what their values must be. +* The `windows_subsystem` attribute specifies that it only works on Windows platforms. +* Inline assembly and the `target_feature` attribute specify the architectures that are supported. + +### Editions + +The main text and flow should document only the current edition. Whenever there is a difference between editions, the differences should be called out with an "Edition Differences" block. diff --git a/docs/review-policy.md b/docs/review-policy.md new file mode 100644 index 0000000..f7bdeb1 --- /dev/null +++ b/docs/review-policy.md @@ -0,0 +1,47 @@ +Team members are given permission to merge changes from other contributors in the repository. There are different guidelines for reviewing based on the kind of changes being made: + +## Policy changes + +- Significant changes to the policy of how the team operates, such as changes to this document, should have agreement of the team without any blocking objections. +- Minor changes to something like the style enforcement can be made with the review of a team member, as long as there is high confidence that it is unlikely any team member would object (for example, codifying a guideline that is already in practice), and that the change can be easily reversed. + +## Meaningful content addition or changes + +- When adding or changing content in the spec, the reviewer should consult with appropriate experts to validate the changes. This may not be required if the reviewer has high confidence that the changes are correct, and consider themselves well-versed enough in the topic to understand it, or the relevant experts are the author or have been heavily involved in the process. It is up to the reviewer to use their best judgement when to consult. +- Content should always follow the guidelines from the [authoring guide]. + +## Minor content changes +- Minor content changes, such as small cleanups or wording fixes, can be made with the review from a team member without further consultation. + +## Tooling changes +- Minor changes to the tooling may be made with a review from a team member. This includes bug fixes, minor additions that are unlikely to have objections, and additions that have already been discussed. +- Major changes, such as a change in how content is authored, or major changes to how the tooling works should be approved by the team without blocking objections. + +## Review Process Flowchart + +When reviewing a pull request, ask yourself the following questions: + +### Are the proposed changes true? + +If we're not sure and can't easily verify it ourselves, we ask someone who would know. + +### Does this make any new guarantees about the language? + +If this would make a new guarantee about the language, this needs to go through the `lang` team to be accepted (unless the `lang` team has clearly accepted this guarantee elsewhere). Ask @traviscross or @pnkfelix if at all unsure about any of these. + +### Would we have added this to the Reference ourselves? + +There are a number of PRs that might be true, but when we look at them, we think to ourselves, in our heart of hearts, that this just isn't something we would have bothered to write ourselves. We don't want to accept a PR just because it's in front of us and not obviously false. It should clearly add value. + +### Is this editorially sound? + +Some PRs try to "sell" the language too much, or try to explain more (or less) than needed, or give too many (or too few) examples, etc. The PR should match the general flavor of the Reference here. + +### Is this well written? + +Some PRs are right but are awkwardly worded or have typographical problems. If the changes are small, we'll just add commits to the branch to clean things up, then merge. + + +This policy does not yet cover the process for getting final approval from the relevant teams. + +[authoring guide]: authoring.md \ No newline at end of file diff --git a/mdbook-spec/.gitignore b/mdbook-spec/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/mdbook-spec/.gitignore @@ -0,0 +1 @@ +/target diff --git a/mdbook-spec/CHANGELOG.md b/mdbook-spec/CHANGELOG.md new file mode 100644 index 0000000..53eaf0f --- /dev/null +++ b/mdbook-spec/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog + +## mdbook-spec 0.1.2 + +- Fixed some issues with rust-lang/rust build integration. + +## mdbook-spec 0.1.1 + +- Moved code to a library to support upstream integration. + +## mdbook-spec 0.1.0 + +- Initial release diff --git a/mdbook-spec/Cargo.lock b/mdbook-spec/Cargo.lock new file mode 100644 index 0000000..1fc0efa --- /dev/null +++ b/mdbook-spec/Cargo.lock @@ -0,0 +1,988 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + +[[package]] +name = "anyhow" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "cc" +version = "1.0.104" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74b6a57f98764a267ff415d50a25e6e166f3831a5071af4995296ea97d210490" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "windows-targets 0.52.6", +] + +[[package]] +name = "clap" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_complete" +version = "4.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d598e88f6874d4b888ed40c71efbcbf4076f1dfbae128a08a8c9e45f710605d" +dependencies = [ + "clap", +] + +[[package]] +name = "clap_lex" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b82cf0babdbd58558212896d1a4272303a57bdb245c2bf1147185fb45640e70" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "core-foundation-sys" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dbus" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb21987b9fb1613058ba3843121dd18b163b254d8a6e797e144cbac14d96d1b" +dependencies = [ + "libc", + "libdbus-sys", + "winapi", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "env_filter" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b35839ba51819680ba087cd351788c9a3c476841207e0b8cee0b04722343b9" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "humantime", + "log", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "handlebars" +version = "5.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b" +dependencies = [ + "log", + "pest", + "pest_derive", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "libdbus-sys" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06085512b750d640299b79be4bad3d2fa90a9c00b1fd9e1b46364f66f0485c72" +dependencies = [ + "cc", + "pkg-config", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + +[[package]] +name = "log" +version = "0.4.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" + +[[package]] +name = "mdbook" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5" +dependencies = [ + "anyhow", + "chrono", + "clap", + "clap_complete", + "env_logger", + "handlebars", + "log", + "memchr", + "once_cell", + "opener", + "pulldown-cmark", + "regex", + "serde", + "serde_json", + "shlex", + "tempfile", + "toml", + "topological-sort", +] + +[[package]] +name = "mdbook-spec" +version = "0.1.2" +dependencies = [ + "anyhow", + "mdbook", + "once_cell", + "pathdiff", + "regex", + "semver", + "serde_json", + "tempfile", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "normpath" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5831952a9476f2fed74b77d74182fa5ddc4d21c72ec45a333b250e3ed0272804" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "opener" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8df34be653210fbe9ffaff41d3b92721c56ce82dfee58ee684f9afb5e3a90c0" +dependencies = [ + "bstr", + "dbus", + "normpath", + "windows-sys 0.52.0", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pest" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd53dff83f26735fdc1ca837098ccf133605d794cdae66acfc2bfac3ec809d95" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a548d2beca6773b1c244554d36fcf8548a8a58e74156968211567250e48e49a" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c93a82e8d145725dcbaf44e5ea887c8a869efdcc28706df2d08c69e17077183" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pest_meta" +version = "2.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a941429fea7e08bedec25e4f6785b6ffaacc6b755da98df5ef3e7dcf4a124c4f" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pulldown-cmark" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76979bea66e7875e7509c4ec5300112b316af87fa7a252ca91c448b32dfe3993" +dependencies = [ + "bitflags", + "memchr", + "pulldown-cmark-escape", + "unicase", +] + +[[package]] +name = "pulldown-cmark-escape" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd348ff538bc9caeda7ee8cad2d1d48236a1f443c1fa3913c6a02fe0043b1dd3" + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "semver" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "serde" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.203" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.120" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "901fa70d88b9d6c98022e23b4136f9f3e54e4662c3bc1bd1d84a42a9a0f0c1e9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tempfile" +version = "3.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" +dependencies = [ + "cfg-if", + "fastrand", + "rustix", + "windows-sys 0.52.0", +] + +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "thiserror" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "topological-sort" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea68304e134ecd095ac6c3574494fc62b909f416c4fca77e440530221e549d3d" + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "unicase" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "wasm-bindgen" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.92" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/mdbook-spec/Cargo.toml b/mdbook-spec/Cargo.toml new file mode 100644 index 0000000..a81915d --- /dev/null +++ b/mdbook-spec/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "mdbook-spec" +version = "0.1.2" +edition = "2021" +license = "MIT OR Apache-2.0" +description = "An mdBook preprocessor to help with the Rust specification." +repository = "https://github.com/rust-lang/spec/" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0.79" +mdbook = { version = "0.4.36", default-features = false } +once_cell = "1.19.0" +pathdiff = "0.2.1" +regex = "1.9.4" +semver = "1.0.21" +serde_json = "1.0.113" +tempfile = "3.10.1" diff --git a/mdbook-spec/LICENSE-APACHE b/mdbook-spec/LICENSE-APACHE new file mode 100644 index 0000000..1b5ec8b --- /dev/null +++ b/mdbook-spec/LICENSE-APACHE @@ -0,0 +1,176 @@ + 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 diff --git a/mdbook-spec/LICENSE-MIT b/mdbook-spec/LICENSE-MIT new file mode 100644 index 0000000..1653b5c --- /dev/null +++ b/mdbook-spec/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2024 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. diff --git a/mdbook-spec/README.md b/mdbook-spec/README.md new file mode 100644 index 0000000..1dce212 --- /dev/null +++ b/mdbook-spec/README.md @@ -0,0 +1,5 @@ +# mdbook-spec + +This is an mdbook preprocessor to add some extensions for the Rust specification. + +> This crate is maintained by the [rust-lang/spec](https://github.com/rust-lang/spec/) team, primarily for use by the Rust Specification and not intended for external use (except as a transitive dependency). This crate may make major changes to its APIs or be deprecated without warning. diff --git a/mdbook-spec/src/lib.rs b/mdbook-spec/src/lib.rs new file mode 100644 index 0000000..6591e41 --- /dev/null +++ b/mdbook-spec/src/lib.rs @@ -0,0 +1,172 @@ +use mdbook::book::{Book, Chapter}; +use mdbook::errors::Error; +use mdbook::preprocess::{CmdPreprocessor, Preprocessor, PreprocessorContext}; +use mdbook::BookItem; +use once_cell::sync::Lazy; +use regex::{Captures, Regex}; +use semver::{Version, VersionReq}; +use std::collections::BTreeMap; +use std::io; +use std::path::PathBuf; + +mod std_links; + +/// The Regex for rules like `r[foo]`. +static RULE_RE: Lazy = Lazy::new(|| Regex::new(r"(?m)^r\[([^]]+)]$").unwrap()); + +/// The Regex for the syntax for blockquotes that have a specific CSS class, +/// like `> [!WARNING]`. +static ADMONITION_RE: Lazy = Lazy::new(|| { + Regex::new(r"(?m)^ *> \[!(?[^]]+)\]\n(?
(?: *> .*\n)+)").unwrap() +}); + +pub fn handle_preprocessing(pre: &dyn Preprocessor) -> Result<(), Error> { + let (ctx, book) = CmdPreprocessor::parse_input(io::stdin())?; + + let book_version = Version::parse(&ctx.mdbook_version)?; + let version_req = VersionReq::parse(mdbook::MDBOOK_VERSION)?; + + if !version_req.matches(&book_version) { + eprintln!( + "warning: The {} plugin was built against version {} of mdbook, \ + but we're being called from version {}", + pre.name(), + mdbook::MDBOOK_VERSION, + ctx.mdbook_version + ); + } + + let processed_book = pre.run(&ctx, book)?; + serde_json::to_writer(io::stdout(), &processed_book)?; + + Ok(()) +} + +pub struct Spec { + /// Whether or not warnings should be errors (set by SPEC_DENY_WARNINGS + /// environment variable). + deny_warnings: bool, +} + +impl Spec { + pub fn new() -> Spec { + Spec { + deny_warnings: std::env::var("SPEC_DENY_WARNINGS").as_deref() == Ok("1"), + } + } + + /// Converts lines that start with `r[…]` into a "rule" which has special + /// styling and can be linked to. + fn rule_definitions( + &self, + chapter: &Chapter, + found_rules: &mut BTreeMap, + ) -> String { + let source_path = chapter.source_path.clone().unwrap_or_default(); + let path = chapter.path.clone().unwrap_or_default(); + RULE_RE + .replace_all(&chapter.content, |caps: &Captures<'_>| { + let rule_id = &caps[1]; + if let Some((old, _)) = + found_rules.insert(rule_id.to_string(), (source_path.clone(), path.clone())) + { + let message = format!( + "rule `{rule_id}` defined multiple times\n\ + First location: {old:?}\n\ + Second location: {source_path:?}" + ); + if self.deny_warnings { + panic!("error: {message}"); + } else { + eprintln!("warning: {message}"); + } + } + format!( + "
\ + [{rule_id}]\ +
\n" + ) + }) + .to_string() + } + + /// Generates link references to all rules on all pages, so you can easily + /// refer to rules anywhere in the book. + fn auto_link_references( + &self, + chapter: &Chapter, + found_rules: &BTreeMap, + ) -> String { + let current_path = chapter.path.as_ref().unwrap().parent().unwrap(); + let definitions: String = found_rules + .iter() + .map(|(rule_id, (_, path))| { + let relative = pathdiff::diff_paths(path, current_path).unwrap(); + format!("[{rule_id}]: {}#{rule_id}\n", relative.display()) + }) + .collect(); + format!( + "{}\n\ + {definitions}", + chapter.content + ) + } + + /// Converts blockquotes with special headers into admonitions. + /// + /// The blockquote should look something like: + /// + /// ```markdown + /// > [!WARNING] + /// > ... + /// ``` + /// + /// This will add a `
` around the blockquote so that + /// it can be styled differently. Any text between the brackets that can + /// be a CSS class is valid. The actual styling needs to be added in a CSS + /// file. + fn admonitions(&self, chapter: &Chapter) -> String { + ADMONITION_RE + .replace_all(&chapter.content, |caps: &Captures<'_>| { + let lower = caps["admon"].to_lowercase(); + format!( + "
\n\n{}\n\n
\n", + &caps["blockquote"] + ) + }) + .to_string() + } +} + +impl Preprocessor for Spec { + fn name(&self) -> &str { + "spec" + } + + fn run(&self, _ctx: &PreprocessorContext, mut book: Book) -> Result { + let mut found_rules = BTreeMap::new(); + book.for_each_mut(|item| { + let BookItem::Chapter(ch) = item else { + return; + }; + if ch.is_draft_chapter() { + return; + } + ch.content = self.rule_definitions(&ch, &mut found_rules); + ch.content = self.admonitions(&ch); + ch.content = std_links::std_links(&ch); + }); + // This is a separate pass because it relies on the modifications of + // the previous passes. + book.for_each_mut(|item| { + let BookItem::Chapter(ch) = item else { + return; + }; + if ch.is_draft_chapter() { + return; + } + ch.content = self.auto_link_references(&ch, &found_rules); + }); + Ok(book) + } +} diff --git a/mdbook-spec/src/main.rs b/mdbook-spec/src/main.rs new file mode 100644 index 0000000..56e11d7 --- /dev/null +++ b/mdbook-spec/src/main.rs @@ -0,0 +1,21 @@ +fn main() { + let mut args = std::env::args().skip(1); + match args.next().as_deref() { + Some("supports") => { + // Supports all renderers. + return; + } + Some(arg) => { + eprintln!("unknown argument: {arg}"); + std::process::exit(1); + } + None => {} + } + + let preprocessor = mdbook_spec::Spec::new(); + + if let Err(e) = mdbook_spec::handle_preprocessing(&preprocessor) { + eprintln!("{}", e); + std::process::exit(1); + } +} diff --git a/mdbook-spec/src/std_links.rs b/mdbook-spec/src/std_links.rs new file mode 100644 index 0000000..0c7860b --- /dev/null +++ b/mdbook-spec/src/std_links.rs @@ -0,0 +1,215 @@ +use mdbook::book::Chapter; +use once_cell::sync::Lazy; +use regex::{Captures, Regex}; +use std::collections::HashSet; +use std::fmt::Write as _; +use std::fs; +use std::io::{self, Write as _}; +use std::process::{self, Command}; +use tempfile::TempDir; + +/// A markdown link (without the brackets) that might possibly be a link to +/// the standard library using rustdoc's intra-doc notation. +const STD_LINK: &str = r"(?: [a-z]+@ )? + (?: std|core|alloc|proc_macro|test ) + (?: ::[A-Za-z0-9_!,:<>{}()\[\]]+ )?"; + +/// The Regex for a markdown link that might be a link to the standard library. +static STD_LINK_RE: Lazy = Lazy::new(|| { + Regex::new(&format!( + r"(?x) + (?: + ( \[`[^`]+`\] ) \( ({STD_LINK}) \) + ) + | (?: + ( \[`{STD_LINK}`\] ) + ) + " + )) + .unwrap() +}); + +/// The Regex used to extract the std links from the HTML generated by rustdoc. +static STD_LINK_EXTRACT_RE: Lazy = + Lazy::new(|| Regex::new(r#"
  • ]*href="(https://doc.rust-lang.org/[^"]+)""#).unwrap()); + +/// The Regex for a markdown link definition. +static LINK_DEF_RE: Lazy = Lazy::new(|| { + // This is a pretty lousy regex for a link definition. It doesn't + // handle things like blockquotes, code blocks, etc. Using a + // markdown parser isn't really feasible here, it would be nice to + // improve this. + Regex::new(r#"(?m)^(? {} + +fn use_my_trait(_: impl ImportantTrait) {} + +fn main() { + use_my_trait(String::new()); +} +``` + +the compiler may generate an error message which looks like this: + +```text +error[E0277]: My Message for `ImportantTrait` implemented for `String` + --> src/main.rs:14:18 + | +14 | use_my_trait(String::new()); + | ------------ ^^^^^^^^^^^^^ My Label + | | + | required by a bound introduced by this call + | + = help: the trait `ImportantTrait` is not implemented for `String` + = note: Note 1 + = note: Note 2 +``` + +[`std::fmt`]: ../../std/fmt/index.html [Clippy]: https://github.com/rust-lang/rust-clippy [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaListPaths_]: ../attributes.md#meta-item-attribute-syntax @@ -309,6 +500,7 @@ When used on a function in a trait implementation, the attribute does nothing. [attributes]: ../attributes.md [block expression]: ../expressions/block-expr.md [call expression]: ../expressions/call-expr.md +[dyn trait]: ../types/trait-object.md [enum variant]: ../items/enumerations.md [enum]: ../items/enumerations.md [expression statement]: ../statements.md#expression-statements diff --git a/src/attributes/limits.md b/src/attributes/limits.md index 65cb55b..79f292a 100644 --- a/src/attributes/limits.md +++ b/src/attributes/limits.md @@ -35,6 +35,10 @@ a!{} ## The `type_length_limit` attribute +> **Note**: This limit is only enforced when the nightly `-Zenforce-type-length-limit` flag is active. +> +> For more information, see . + The *`type_length_limit` attribute* limits the maximum number of type substitutions made when constructing a concrete type during monomorphization. It is applied at the [crate] level, and uses the [_MetaNameValueStr_] syntax @@ -42,7 +46,7 @@ to set the limit based on the number of type substitutions. > Note: The default in `rustc` is 1048576. -```rust,compile_fail +```rust,ignore #![type_length_limit = "4"] fn f(x: T) {} diff --git a/src/attributes/testing.md b/src/attributes/testing.md index e0181b1..2c3b292 100644 --- a/src/attributes/testing.md +++ b/src/attributes/testing.md @@ -9,16 +9,11 @@ enables the [`test` conditional compilation option]. The *`test` attribute* marks a function to be executed as a test. These functions are only compiled when in test mode. Test functions must be free, -monomorphic functions that take no arguments, and the return type must be one -of the following: +monomorphic functions that take no arguments, and the return type must implement the [`Termination`] trait, for example: * `()` -* `Result<(), E> where E: Error` - - - -> Note: The implementation of which return types are allowed is determined by -> the unstable [`Termination`] trait. +* `Result where T: Termination, E: Debug` +* `!` @@ -26,9 +21,12 @@ of the following: > Note: The test mode is enabled by passing the `--test` argument to `rustc` > or using `cargo test`. -Tests that return `()` pass as long as they terminate and do not panic. Tests -that return a `Result<(), E>` pass as long as they return `Ok(())`. Tests that -do not terminate neither pass nor fail. +The test harness calls the returned value's [`report`] method, and classifies the test as passed or failed depending on whether the resulting [`ExitCode`] represents successful termination. +In particular: +* Tests that return `()` pass as long as they terminate and do not panic. +* Tests that return a `Result<(), E>` pass as long as they return `Ok(())`. +* Tests that return `ExitCode::SUCCESS` pass, and tests that return `ExitCode::FAILURE` fail. +* Tests that do not terminate neither pass nor fail. ```rust # use std::io; @@ -85,5 +83,7 @@ fn mytest() { [_MetaListNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [_MetaNameValueStr_]: ../attributes.md#meta-item-attribute-syntax [`Termination`]: ../../std/process/trait.Termination.html +[`report`]: ../../std/process/trait.Termination.html#tymethod.report [`test` conditional compilation option]: ../conditional-compilation.md#test [attributes]: ../attributes.md +[`ExitCode`]: ../../std/process/struct.ExitCode.html diff --git a/src/attributes/type_system.md b/src/attributes/type_system.md index 729069d..dd3ea98 100644 --- a/src/attributes/type_system.md +++ b/src/attributes/type_system.md @@ -20,6 +20,12 @@ pub struct Config { pub window_height: u16, } +#[non_exhaustive] +pub struct Token; + +#[non_exhaustive] +pub struct Id(pub u64); + #[non_exhaustive] pub enum Error { Message(String), @@ -34,11 +40,13 @@ pub enum Message { // Non-exhaustive structs can be constructed as normal within the defining crate. let config = Config { window_width: 640, window_height: 480 }; +let token = Token; +let id = Id(4); // Non-exhaustive structs can be matched on exhaustively within the defining crate. -if let Config { window_width, window_height } = config { - // ... -} +let Config { window_width, window_height } = config; +let Token = token; +let Id(id_number) = id; let error = Error::Other; let message = Message::Reaction(3); @@ -64,30 +72,49 @@ Non-exhaustive types cannot be constructed outside of the defining crate: - Non-exhaustive variants ([`struct`][struct] or [`enum` variant][enum]) cannot be constructed with a [_StructExpression_] \(including with [functional update syntax]). +- The implicitly defined same-named constant of a [unit-like struct][struct], + or the same-named constructor function of a [tuple struct][struct], + has a [visibility] no greater than `pub(crate)`. + That is, if the struct’s visibility is `pub`, then the constant or constructor’s visibility + is `pub(crate)`, and otherwise the visibility of the two items is the same + (as is the case without `#[non_exhaustive]`). - [`enum`][enum] instances can be constructed. +The following examples of construction do not compile when outside the defining crate: + ```rust,ignore -// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been -// annotated as `#[non_exhaustive]`. -use upstream::{Config, Error, Message}; +// These are types defined in an upstream crate that have been annotated as +// `#[non_exhaustive]`. +use upstream::{Config, Token, Id, Error, Message}; -// Cannot construct an instance of `Config`, if new fields were added in +// Cannot construct an instance of `Config`; if new fields were added in // a new version of `upstream` then this would fail to compile, so it is // disallowed. let config = Config { window_width: 640, window_height: 480 }; -// Can construct an instance of `Error`, new variants being introduced would +// Cannot construct an instance of `Token`; if new fields were added, then +// it would not be a unit-like struct any more, so the same-named constant +// created by it being a unit-like struct is not public outside the crate; +// this code fails to compile. +let token = Token; + +// Cannot construct an instance of `Id`; if new fields were added, then +// its constructor function signature would change, so its constructor +// function is not public outside the crate; this code fails to compile. +let id = Id(5); + +// Can construct an instance of `Error`; new variants being introduced would // not result in this failing to compile. let error = Error::Message("foo".to_string()); -// Cannot construct an instance of `Message::Send` or `Message::Reaction`, +// Cannot construct an instance of `Message::Send` or `Message::Reaction`; // if new fields were added in a new version of `upstream` then this would // fail to compile, so it is disallowed. let message = Message::Send { from: 0, to: 1, contents: "foo".to_string(), }; let message = Message::Reaction(0); -// Cannot construct an instance of `Message::Quit`, if this were converted to +// Cannot construct an instance of `Message::Quit`; if this were converted to // a tuple-variant `upstream` then this would fail to compile. let message = Message::Quit; ``` @@ -95,16 +122,18 @@ let message = Message::Quit; There are limitations when matching on non-exhaustive types outside of the defining crate: - When pattern matching on a non-exhaustive variant ([`struct`][struct] or [`enum` variant][enum]), - a [_StructPattern_] must be used which must include a `..`. Tuple variant constructor visibility - is lowered to `min($vis, pub(crate))`. + a [_StructPattern_] must be used which must include a `..`. A tuple variant's constructor's + [visibility] is reduced to be no greater than `pub(crate)`. - When pattern matching on a non-exhaustive [`enum`][enum], matching on a variant does not contribute towards the exhaustiveness of the arms. +The following examples of matching do not compile when outside the defining crate: + ```rust, ignore -// `Config`, `Error`, and `Message` are types defined in an upstream crate that have been -// annotated as `#[non_exhaustive]`. -use upstream::{Config, Error, Message}; +// These are types defined in an upstream crate that have been annotated as +// `#[non_exhaustive]`. +use upstream::{Config, Token, Id, Error, Message}; // Cannot match on a non-exhaustive enum without including a wildcard arm. match error { @@ -118,6 +147,13 @@ if let Ok(Config { window_width, window_height }) = config { // would compile with: `..` } +// Cannot match a non-exhaustive unit-like or tuple struct except by using +// braced struct syntax with a wildcard. +// This would compile as `let Token { .. } = token;` +let Token = token; +// This would compile as `let Id { 0: id_number, .. } = id;` +let Id(id_number) = id; + match message { // Cannot match on a non-exhaustive struct enum variant without including a wildcard. Message::Send { from, to, contents } => { }, @@ -127,6 +163,14 @@ match message { } ``` +It's also not allowed to cast non-exhaustive types from foreign crates. +```rust, ignore +use othercrate::NonExhaustiveEnum; + +// Cannot cast a non-exhaustive enum outside of its defining crate. +let _ = NonExhaustiveEnum::default() as u8; +``` + Non-exhaustive types are always considered inhabited in downstream crates. [_MetaWord_]: ../attributes.md#meta-item-attribute-syntax @@ -139,3 +183,4 @@ Non-exhaustive types are always considered inhabited in downstream crates. [enum]: ../items/enumerations.md [functional update syntax]: ../expressions/struct-expr.md#functional-update-syntax [struct]: ../items/structs.md +[visibility]: ../visibility-and-privacy.md diff --git a/src/behavior-considered-undefined.md b/src/behavior-considered-undefined.md index c4a9980..bee5010 100644 --- a/src/behavior-considered-undefined.md +++ b/src/behavior-considered-undefined.md @@ -14,57 +14,62 @@ undefined behavior, it is *unsound*.
    -***Warning:*** The following list is not exhaustive. There is no formal model of -Rust's semantics for what is and is not allowed in unsafe code, so there may be -more behavior considered unsafe. The following list is just what we know for -sure is undefined behavior. Please read the [Rustonomicon] before writing unsafe -code. +***Warning:*** The following list is not exhaustive; it may grow or shrink. +There is no formal model of Rust's semantics for what is and is not allowed in +unsafe code, so there may be more behavior considered unsafe. We also reserve +the right to make some of the behavior in that list defined in the future. In +other words, this list does not say that anything will *definitely* always be +undefined in all future Rust version (but we might make such commitments for +some list items in the future). + +Please read the [Rustonomicon] before writing unsafe code.
    * Data races. -* Evaluating a [dereference expression] (`*expr`) on a raw pointer that is - [dangling] or unaligned, even in [place expression context] - (e.g. `addr_of!(&*expr)`). -* Breaking the [pointer aliasing rules]. `&mut T` and `&T` follow LLVM’s scoped - [noalias] model, except if the `&T` contains an [`UnsafeCell`]. -* Mutating immutable data. All data inside a [`const`] item is immutable. Moreover, all - data reached through a shared reference or data owned by an immutable binding - is immutable, unless that data is contained within an [`UnsafeCell`]. +* Accessing (loading from or storing to) a place that is [dangling] or [based on + a misaligned pointer]. +* Performing a place projection that violates the requirements of [in-bounds + pointer arithmetic][offset]. A place projection is a [field + expression][project-field], a [tuple index expression][project-tuple], or an + [array/slice index expression][project-slice]. +* Breaking the [pointer aliasing rules]. `Box`, `&mut T` and `&T` follow + LLVM’s scoped [noalias] model, except if the `&T` contains an + [`UnsafeCell`]. References and boxes must not be [dangling] while they are + live. The exact liveness duration is not specified, but some bounds exist: + * For references, the liveness duration is upper-bounded by the syntactic + lifetime assigned by the borrow checker; it cannot be live any *longer* than + that lifetime. + * Each time a reference or box is passed to or returned from a function, it is + considered live. + * When a reference (but not a `Box`!) is passed to a function, it is live at + least as long as that function call, again except if the `&T` contains an + [`UnsafeCell`]. + + All this also applies when values of these + types are passed in a (nested) field of a compound type, but not behind + pointer indirections. +* Mutating immutable bytes. All bytes inside a [`const`] item are immutable. + The bytes owned by an immutable binding or immutable `static` are immutable, unless those bytes are part of an [`UnsafeCell`]. + + Moreover, the bytes [pointed to] by a shared reference, including transitively through other references (both shared and mutable) and `Box`es, are immutable; transitivity includes those references stored in fields of compound types. + + A mutation is any write of more than 0 bytes which overlaps with any of the relevant bytes (even if that write does not change the memory contents). * Invoking undefined behavior via compiler intrinsics. * Executing code compiled with platform features that the current platform does not support (see [`target_feature`]), *except* if the platform explicitly documents this to be safe. * Calling a function with the wrong call ABI or unwinding from a function with the wrong unwind ABI. -* Producing an invalid value, even in private fields and locals. "Producing" a +* Producing an [invalid value][invalid-values]. "Producing" a value happens any time a value is assigned to or read from a place, passed to a function/primitive operation or returned from a function/primitive operation. - The following values are invalid (at their respective type): - * A value other than `false` (`0`) or `true` (`1`) in a [`bool`]. - * A discriminant in an `enum` not included in the type definition. - * A null `fn` pointer. - * A value in a `char` which is a surrogate or above `char::MAX`. - * A `!` (all values are invalid for this type). - * An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer obtained - from [uninitialized memory][undef], or uninitialized memory in a `str`. - * A reference or `Box` that is [dangling], unaligned, or points to an invalid value. - * Invalid metadata in a wide reference, `Box`, or raw pointer: - * `dyn Trait` metadata is invalid if it is not a pointer to a vtable for - `Trait` that matches the actual dynamic trait the pointer or reference points to. - * Slice metadata is invalid if the length is not a valid `usize` - (i.e., it must not be read from uninitialized memory). - * Invalid values for a type with a custom definition of invalid values. - In the standard library, this affects [`NonNull`] and [`NonZero*`]. - - > **Note**: `rustc` achieves this with the unstable - > `rustc_layout_scalar_valid_range_*` attributes. * Incorrect use of inline assembly. For more details, refer to the [rules] to follow when writing code that uses inline assembly. - -**Note:** Uninitialized memory is also implicitly invalid for any type that has -a restricted set of valid values. In other words, the only cases in which -reading uninitialized memory is permitted are inside `union`s and in "padding" -(the gaps between the fields/elements of a type). +* **In [const context](const_eval.md#const-context)**: transmuting or otherwise + reinterpreting a pointer (reference, raw pointer, or function pointer) into + some allocated object as a non-pointer type (such as integers). + 'Reinterpreting' refers to loading the pointer value at integer type without a + cast, e.g. by doing raw pointer casts or using a union. > **Note**: Undefined behavior affects the entire program. For example, calling > a function in C that exhibits undefined behavior of C means your entire @@ -72,17 +77,98 @@ reading uninitialized memory is permitted are inside `union`s and in "padding" > vice versa, undefined behavior in Rust can cause adverse affects on code > executed by any FFI calls to other languages. +### Pointed-to bytes + +The span of bytes a pointer or reference "points to" is determined by the pointer value and the size of the pointee type (using `size_of_val`). + +### Places based on misaligned pointers +[based on a misaligned pointer]: #places-based-on-misaligned-pointers + +A place is said to be "based on a misaligned pointer" if the last `*` projection +during place computation was performed on a pointer that was not aligned for its +type. (If there is no `*` projection in the place expression, then this is +accessing the field of a local and rustc will guarantee proper alignment. If +there are multiple `*` projection, then each of them incurs a load of the +pointer-to-be-dereferenced itself from memory, and each of these loads is +subject to the alignment constraint. Note that some `*` projections can be +omitted in surface Rust syntax due to automatic dereferencing; we are +considering the fully expanded place expression here.) + +For instance, if `ptr` has type `*const S` where `S` has an alignment of 8, then +`ptr` must be 8-aligned or else `(*ptr).f` is "based on an misaligned pointer". +This is true even if the type of the field `f` is `u8` (i.e., a type with +alignment 1). In other words, the alignment requirement derives from the type of +the pointer that was dereferenced, *not* the type of the field that is being +accessed. + +Note that a place based on a misaligned pointer only leads to Undefined Behavior +when it is loaded from or stored to. `addr_of!`/`addr_of_mut!` on such a place +is allowed. `&`/`&mut` on a place requires the alignment of the field type (or +else the program would be "producing an invalid value"), which generally is a +less restrictive requirement than being based on an aligned pointer. Taking a +reference will lead to a compiler error in cases where the field type might be +more aligned than the type that contains it, i.e., `repr(packed)`. This means +that being based on an aligned pointer is always sufficient to ensure that the +new reference is aligned, but it is not always necessary. + ### Dangling pointers [dangling]: #dangling-pointers -A reference/pointer is "dangling" if it is null or not all of the bytes it -points to are part of the same allocation (so in particular they all have to be -part of *some* allocation). The span of bytes it points to is determined by the -pointer value and the size of the pointee type (using `size_of_val`). As a -consequence, if the span is empty, "dangling" is the same as "non-null". Note -that slices and strings point to their entire range, so it is important that the length -metadata is never too large. In particular, allocations and therefore slices and strings -cannot be bigger than `isize::MAX` bytes. +A reference/pointer is "dangling" if not all of the bytes it +[points to] are part of the same live allocation (so in particular they all have to be +part of *some* allocation). + +If the size is 0, then the pointer is trivially never "dangling" +(even if it is a null pointer). + +Note that dynamically sized types (such as slices and strings) point to their +entire range, so it is important that the length metadata is never too large. In +particular, the dynamic size of a Rust value (as determined by `size_of_val`) +must never exceed `isize::MAX`, since it is impossible for a single allocation +to be larger than `isize::MAX`. + +### Invalid values +[invalid-values]: #invalid-values + +The Rust compiler assumes that all values produced during program execution are +"valid", and producing an invalid value is hence immediate UB. + +Whether a value is valid depends on the type: +* A [`bool`] value must be `false` (`0`) or `true` (`1`). +* A `fn` pointer value must be non-null. +* A `char` value must not be a surrogate (i.e., must not be in the range `0xD800..=0xDFFF`) and must be equal to or less than `char::MAX`. +* A `!` value must never exist. +* An integer (`i*`/`u*`), floating point value (`f*`), or raw pointer must be + initialized, i.e., must not be obtained from [uninitialized memory][undef]. +* A `str` value is treated like `[u8]`, i.e. it must be initialized. +* An `enum` must have a valid discriminant, and all fields of the variant indicated by that discriminant must be valid at their respective type. +* A `struct`, tuple, and array requires all fields/elements to be valid at their respective type. +* For a `union`, the exact validity requirements are not decided yet. + Obviously, all values that can be created entirely in safe code are valid. + If the union has a zero-sized field, then every possible value is valid. + Further details are [still being debated](https://github.com/rust-lang/unsafe-code-guidelines/issues/438). +* A reference or [`Box`] must be aligned, it cannot be [dangling], and it must point to a valid value + (in case of dynamically sized types, using the actual dynamic type of the + pointee as determined by the metadata). + Note that the last point (about pointing to a valid value) remains a subject of some debate. +* The metadata of a wide reference, [`Box`], or raw pointer must match + the type of the unsized tail: + * `dyn Trait` metadata must be a pointer to a compiler-generated vtable for `Trait`. + (For raw pointers, this requirement remains a subject of some debate.) + * Slice (`[T]`) metadata must be a valid `usize`. + Furthermore, for wide references and [`Box`], slice metadata is invalid + if it makes the total size of the pointed-to value bigger than `isize::MAX`. +* If a type has a custom range of a valid values, then a valid value must be in that range. + In the standard library, this affects [`NonNull`] and [`NonZero`]. + + > **Note**: `rustc` achieves this with the unstable + > `rustc_layout_scalar_valid_range_*` attributes. + +**Note:** Uninitialized memory is also implicitly invalid for any type that has +a restricted set of valid values. In other words, the only cases in which +reading uninitialized memory is permitted are inside `union`s and in "padding" +(the gaps between the fields of a type). + [`bool`]: types/boolean.md [`const`]: items/constant-items.md @@ -93,7 +179,13 @@ cannot be bigger than `isize::MAX` bytes. [`UnsafeCell`]: ../std/cell/struct.UnsafeCell.html [Rustonomicon]: ../nomicon/index.html [`NonNull`]: ../core/ptr/struct.NonNull.html -[`NonZero*`]: ../core/num/index.html -[dereference expression]: expressions/operator-expr.md#the-dereference-operator +[`NonZero`]: ../core/num/struct.NonZero.html +[`Box`]: ../alloc/boxed/struct.Box.html [place expression context]: expressions.md#place-expressions-and-value-expressions [rules]: inline-assembly.md#rules-for-inline-assembly +[points to]: #pointed-to-bytes +[pointed to]: #pointed-to-bytes +[offset]: ../std/primitive.pointer.html#method.offset +[project-field]: expressions/field-expr.md +[project-tuple]: expressions/tuple-expr.md#tuple-indexing-expressions +[project-slice]: expressions/array-expr.md#array-and-slice-indexing-expressions diff --git a/src/comments.md b/src/comments.md index ff15950..795bf63 100644 --- a/src/comments.md +++ b/src/comments.md @@ -2,7 +2,7 @@ > **Lexer**\ > LINE_COMMENT :\ ->       `//` (~\[`/` `!`] | `//`) ~`\n`\*\ +>       `//` (~\[`/` `!` `\n`] | `//`) ~`\n`\*\ >    | `//` > > BLOCK_COMMENT :\ @@ -30,11 +30,11 @@ >    | INNER_BLOCK_DOC > > _IsolatedCR_ :\ ->    _A `\r` not followed by a `\n`_ +>    \\r ## Non-doc comments -Comments in Rust code follow the general C++ style of line (`//`) and +Comments follow the general C++ style of line (`//`) and block (`/* ... */`) comment forms. Nested block comments are supported. Non-doc comments are interpreted as a form of whitespace. @@ -42,7 +42,7 @@ Non-doc comments are interpreted as a form of whitespace. ## Doc comments Line doc comments beginning with exactly _three_ slashes (`///`), and block -doc comments (`/** ... */`), both inner doc comments, are interpreted as a +doc comments (`/** ... */`), both outer doc comments, are interpreted as a special syntax for [`doc` attributes]. That is, they are equivalent to writing `#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into `#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. @@ -53,8 +53,9 @@ that follows. That is, they are equivalent to writing `#![doc="..."]` around the body of the comment. `//!` comments are usually used to document modules that occupy a source file. -Isolated CRs (`\r`), i.e. not followed by LF (`\n`), are not allowed in doc -comments. +The character `U+000D` (CR) is not allowed in doc comments. + +> **Note**: The sequence `U+000D` (CR) immediately followed by `U+000A` (LF) would have been previously transformed into a single `U+000A` (LF). ## Examples diff --git a/src/conditional-compilation.md b/src/conditional-compilation.md index 6966cec..f98b323 100644 --- a/src/conditional-compilation.md +++ b/src/conditional-compilation.md @@ -22,42 +22,29 @@ > _ConfigurationPredicateList_\ >    _ConfigurationPredicate_ (`,` _ConfigurationPredicate_)\* `,`? -*Conditionally compiled source code* is source code that may or may not be -considered a part of the source code depending on certain conditions. Source code can be conditionally compiled -using the [attributes] [`cfg`] and [`cfg_attr`] and the built-in [`cfg` macro]. -These conditions are based on the target architecture of the compiled crate, -arbitrary values passed to the compiler, and a few other miscellaneous things -further described below in detail. +*Conditionally compiled source code* is source code that is compiled only under certain conditions. Source code can be made conditionally compiled using the [`cfg`] and [`cfg_attr`] [attributes] and the built-in [`cfg` macro]. Whether to compile can depend on the target architecture of the compiled crate, arbitrary values passed to the compiler, and other things further described below. Each form of conditional compilation takes a _configuration predicate_ that evaluates to true or false. The predicate is one of the following: -* A configuration option. It is true if the option is set and false if it is - unset. -* `all()` with a comma separated list of configuration predicates. It is false - if at least one predicate is false. If there are no predicates, it is true. -* `any()` with a comma separated list of configuration predicates. It is true - if at least one predicate is true. If there are no predicates, it is false. -* `not()` with a configuration predicate. It is true if its predicate is false - and false if its predicate is true. +* A configuration option. The predicate is true if the option is set, and false if it is unset. +* `all()` with a comma-separated list of configuration predicates. It is true if all of the given predicates are true, or if the list is empty. +* `any()` with a comma-separated list of configuration predicates. It is true if at least one of the given predicates is true. If there are no predicates, it is false. +* `not()` with a configuration predicate. It is true if its predicate is false and false if its predicate is true. -_Configuration options_ are names and key-value pairs that are either set or -unset. Names are written as a single identifier such as, for example, `unix`. -Key-value pairs are written as an identifier, `=`, and then a string. For -example, `target_arch = "x86_64"` is a configuration option. +_Configuration options_ are either names or key-value pairs, and are either set or unset. +Names are written as a single identifier, such as `unix`. +Key-value pairs are written as an identifier, `=`, and then a string, such as `target_arch = "x86_64"`. -> **Note**: Whitespace around the `=` is ignored. `foo="bar"` and `foo = "bar"` -> are equivalent configuration options. +> **Note**: Whitespace around the `=` is ignored, so `foo="bar"` and `foo = "bar"` are equivalent. -Keys are not unique in the set of key-value configuration options. For example, -both `feature = "std"` and `feature = "serde"` can be set at the same time. +Keys do not need to be unique. For example, both `feature = "std"` and `feature = "serde"` can be set at the same time. ## Set Configuration Options Which configuration options are set is determined statically during the -compilation of the crate. Certain options are _compiler-set_ based on data -about the compilation. Other options are _arbitrarily-set_, set based on input +compilation of the crate. Some options are _compiler-set_ based on data +about the compilation. Other options are _arbitrarily-set_ based on input passed to the compiler outside of the code. It is not possible to set a configuration option from within the source code of the crate being compiled. @@ -70,11 +57,7 @@ configuration option from within the source code of the crate being compiled.
    -Warning: It is possible for arbitrarily-set configuration options to have the -same value as compiler-set configuration options. For example, it is possible -to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and -have both `unix` and `windows` configuration options set at the same time. It -is unwise to actually do this. +Warning: Arbitrarily-set configuration options can clash with compiler-set configuration options. For example, it is possible to do `rustc --cfg "unix" program.rs` while compiling to a Windows target, and have both `unix` and `windows` configuration options set at the same time. Doing this would be unwise.
    @@ -129,6 +112,7 @@ Example values: * `"dragonfly"` * `"openbsd"` * `"netbsd"` +* `"none"` (typical for embedded targets) ### `target_family` @@ -141,6 +125,7 @@ Example values: * `"unix"` * `"windows"` * `"wasm"` +* Both `"unix"` and `"wasm"` ### `unix` and `windows` @@ -165,6 +150,23 @@ Example values: * `"musl"` * `"sgx"` +### `target_abi` + +Key-value option set to further disambiguate the `target_env` with information +about the target ABI. For historical reasons, +this value is only defined as not the empty-string when actually needed for +disambiguation. Thus, for example, on many GNU platforms, this value will be +empty. + +Example values: + +* `""` +* `"llvm"` +* `"eabihf"` +* `"abi64"` +* `"sim"` +* `"macabi"` + ### `target_endian` Key-value option set once with either a value of "little" or "big" depending @@ -191,6 +193,25 @@ Example values: * `"pc"` * `"unknown"` +### `target_has_atomic` + +Key-value option set for each bit width that the target supports +atomic loads, stores, and compare-and-swap operations. + +When this cfg is present, all of the stable [`core::sync::atomic`] APIs are available for +the relevant atomic width. + +[`core::sync::atomic`]: ../core/sync/atomic/index.html + +Possible values: + +* `"8"` +* `"16"` +* `"32"` +* `"64"` +* `"128"` +* `"ptr"` + ### `test` Enabled when compiling the test harness. Done with `rustc` by using the @@ -235,6 +256,12 @@ It is written as `cfg`, `(`, a configuration predicate, and finally `)`. If the predicate is true, the thing is rewritten to not have the `cfg` attribute on it. If the predicate is false, the thing is removed from the source code. +When a crate-level `cfg` has a false predicate, the behavior is slightly +different: any crate attributes preceding the `cfg` are kept, and any crate +attributes following the `cfg` are removed. This allows `#![no_std]` and +`#![no_core]` crates to avoid linking `std`/`core` even if a `#![cfg(...)]` has +removed the entire crate. + Some examples on functions: ```rust diff --git a/src/const_eval.md b/src/const_eval.md index b46e94e..af8d486 100644 --- a/src/const_eval.md +++ b/src/const_eval.md @@ -27,7 +27,7 @@ to be run. * [Tuple expressions]. * [Array expressions]. * [Struct] expressions. -* [Block expressions], including `unsafe` blocks. +* [Block expressions], including `unsafe` and `const` blocks. * [let statements] and thus irrefutable [patterns], including mutable bindings * [assignment expressions] * [compound assignment expressions] @@ -42,9 +42,8 @@ to be run. * The [dereference operator] except for raw pointers. * [Grouped] expressions. * [Cast] expressions, except - * pointer to address casts, - * function pointer to address casts, and - * unsizing casts to trait objects. + * pointer to address casts and + * function pointer to address casts. * Calls of [const functions] and const methods. * [loop], [while] and [`while let`] expressions. * [if], [`if let`] and [match] expressions. @@ -60,6 +59,7 @@ A _const context_ is one of the following: * [statics] * [enum discriminants] * A [const generic argument] +* A [const block] ## Const Functions @@ -107,6 +107,7 @@ Conversely, the following are possible in a const function, but not in a const c [cast]: expressions/operator-expr.md#type-cast-expressions [closure expressions]: expressions/closure-expr.md [comparison]: expressions/operator-expr.md#comparison-operators +[const block]: expressions/block-expr.md#const-blocks [const functions]: items/functions.md#const-functions [const generic argument]: items/generics.md#const-generics [const generic parameters]: items/generics.md#const-generics @@ -114,7 +115,7 @@ Conversely, the following are possible in a const function, but not in a const c [Const parameters]: items/generics.md [dereference operator]: expressions/operator-expr.md#the-dereference-operator [destructors]: destructors.md -[enum discriminants]: items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations +[enum discriminants]: items/enumerations.md#discriminants [expression statements]: statements.md#expression-statements [expressions]: expressions.md [field]: expressions/field-expr.md diff --git a/src/crates-and-source-files.md b/src/crates-and-source-files.md index 494e454..b0e607b 100644 --- a/src/crates-and-source-files.md +++ b/src/crates-and-source-files.md @@ -2,16 +2,9 @@ > **Syntax**\ > _Crate_ :\ ->    UTF8BOM?\ ->    SHEBANG?\ >    [_InnerAttribute_]\*\ >    [_Item_]\* -> **Lexer**\ -> UTF8BOM : `\uFEFF`\ -> SHEBANG : `#!` \~`\n`\+[†](#shebang) - - > Note: Although Rust, like any other language, can be implemented by an > interpreter as well as a compiler, the only existing implementation is a > compiler, and the language has always been designed to be compiled. For these @@ -53,6 +46,8 @@ that apply to the containing module, most of which influence the behavior of the compiler. The anonymous crate module can have additional attributes that apply to the crate as a whole. +> **Note**: The file's contents may be preceded by a [shebang]. + ```rust // Specify the crate name. #![crate_name = "projx"] @@ -65,53 +60,45 @@ apply to the crate as a whole. #![warn(non_camel_case_types)] ``` -## Byte order mark - -The optional [_UTF8 byte order mark_] (UTF8BOM production) indicates that the -file is encoded in UTF8. It can only occur at the beginning of the file and -is ignored by the compiler. - -## Shebang - -A source file can have a [_shebang_] (SHEBANG production), which indicates -to the operating system what program to use to execute this file. It serves -essentially to treat the source file as an executable script. The shebang -can only occur at the beginning of the file (but after the optional -_UTF8BOM_). It is ignored by the compiler. For example: - - -```rust,ignore -#!/usr/bin/env rustx - -fn main() { - println!("Hello!"); -} -``` - -A restriction is imposed on the shebang syntax to avoid confusion with an -[attribute]. The `#!` characters must not be followed by a `[` token, ignoring -intervening [comments] or [whitespace]. If this restriction fails, then it is -not treated as a shebang, but instead as the start of an attribute. - -## Preludes and `no_std` - -This section has been moved to the [Preludes chapter](names/preludes.md). - - ## Main Functions A crate that contains a `main` [function] can be compiled to an executable. If a `main` function is present, it must take no arguments, must not declare any [trait or lifetime bounds], must not have any [where clauses], and its return -type must be one of the following: +type must implement the [`Termination`] trait. -* `()` -* `Result<(), E> where E: Error` - - +```rust +fn main() {} +``` +```rust +fn main() -> ! { + std::process::exit(0); +} +``` +```rust +fn main() -> impl std::process::Termination { + std::process::ExitCode::SUCCESS +} +``` + +The `main` function may be an import, e.g. from an external crate or from the current one. + +```rust +mod foo { + pub fn bar() { + println!("Hello, world!"); + } +} +use foo::bar as main; +``` -> Note: The implementation of which return types are allowed is determined by -> the unstable [`Termination`] trait. +> **Note**: Types with implementations of [`Termination`] in the standard library include: +> +> * `()` +> * [`!`] +> * [`Infallible`] +> * [`ExitCode`] +> * `Result where T: Termination, E: Debug` @@ -143,21 +130,21 @@ or `_` (U+005F) characters. in the Owens and Flatt module system, or a *configuration* in Mesa. [Unicode alphanumeric]: ../std/primitive.char.html#method.is_alphanumeric +[`!`]: types/never.md [_InnerAttribute_]: attributes.md [_Item_]: items.md [_MetaNameValueStr_]: attributes.md#meta-item-attribute-syntax -[_shebang_]: https://en.wikipedia.org/wiki/Shebang_(Unix) -[_utf8 byte order mark_]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 +[`ExitCode`]: ../std/process/struct.ExitCode.html +[`Infallible`]: ../std/convert/enum.Infallible.html [`Termination`]: ../std/process/trait.Termination.html [attribute]: attributes.md [attributes]: attributes.md -[comments]: comments.md [function]: items/functions.md [module]: items/modules.md [module path]: paths.md +[shebang]: input-format.md#shebang-removal [trait or lifetime bounds]: trait-bounds.md [where clauses]: items/generics.md#where-clauses -[whitespace]: whitespace.md diff --git a/src/expressions/path-expr.md b/src/expressions/path-expr.md index 0909c5d..0707e9d 100644 --- a/src/expressions/path-expr.md +++ b/src/expressions/path-expr.md @@ -23,6 +23,8 @@ let push_integer = Vec::::push; let slice_reverse = <[i32]>::reverse; ``` +Evaluation of associated constants is handled the same way as [`const` blocks]. + [_PathInExpression_]: ../paths.md#paths-in-expressions [_QualifiedPathInExpression_]: ../paths.md#qualified-paths [place expressions]: ../expressions.md#place-expressions-and-value-expressions @@ -30,3 +32,4 @@ let slice_reverse = <[i32]>::reverse; [path]: ../paths.md [`static mut`]: ../items/static-items.md#mutable-statics [`unsafe` block]: block-expr.md#unsafe-blocks +[`const` blocks]: block-expr.md#const-blocks diff --git a/src/expressions/struct-expr.md b/src/expressions/struct-expr.md index 8caeff2..8d91547 100644 --- a/src/expressions/struct-expr.md +++ b/src/expressions/struct-expr.md @@ -73,7 +73,7 @@ drop(y_ref); ``` Struct expressions with curly braces can't be used directly in a [loop] or [if] expression's head, or in the [scrutinee] of an [if let] or [match] expression. -However, struct expressions can be in used in these situations if they are within another expression, for example inside [parentheses]. +However, struct expressions can be used in these situations if they are within another expression, for example inside [parentheses]. The field names can be decimal integer values to specify indices for constructing tuple structs. This can be used with base structs to fill out the remaining indices not specified: diff --git a/src/expressions/underscore-expr.md b/src/expressions/underscore-expr.md index 069f227..d68c6a9 100644 --- a/src/expressions/underscore-expr.md +++ b/src/expressions/underscore-expr.md @@ -8,10 +8,27 @@ Underscore expressions, denoted with the symbol `_`, are used to signify a placeholder in a destructuring assignment. They may only appear in the left-hand side of an assignment. -An example of an `_` expression: +Note that this is distinct from the [wildcard pattern](../patterns.md#wildcard-pattern). + +Examples of `_` expressions: ```rust let p = (1, 2); let mut a = 0; (_, a) = p; + +struct Position { + x: u32, + y: u32, +} + +Position { x: a, y: _ } = Position{ x: 2, y: 3 }; + +// unused result, assignment to `_` used to declare intent and remove a warning +_ = 2 + 2; +// triggers unused_must_use warning +// 2 + 2; + +// equivalent technique using a wildcard pattern in a let-binding +let _ = 2 + 2; ``` diff --git a/src/identifiers.md b/src/identifiers.md index a4e972c..c760f68 100644 --- a/src/identifiers.md +++ b/src/identifiers.md @@ -13,7 +13,7 @@ > NON_KEYWORD_IDENTIFIER | RAW_IDENTIFIER -Identifiers follow the specification in [Unicode Standard Annex #31][UAX31] for Unicode version 13.0, with the additions described below. Some examples of identifiers: +Identifiers follow the specification in [Unicode Standard Annex #31][UAX31] for Unicode version 15.0, with the additions described below. Some examples of identifiers: * `foo` * `_identifier` @@ -68,5 +68,5 @@ keyword except the ones listed above for `RAW_IDENTIFIER`. [proc-macro]: procedural-macros.md [reserved]: keywords.md#reserved-keywords [strict]: keywords.md#strict-keywords -[UAX15]: https://www.unicode.org/reports/tr15/tr15-50.html -[UAX31]: https://www.unicode.org/reports/tr31/tr31-33.html +[UAX15]: https://www.unicode.org/reports/tr15/tr15-53.html +[UAX31]: https://www.unicode.org/reports/tr31/tr31-37.html diff --git a/src/inline-assembly.md b/src/inline-assembly.md index 243887b..56e170b 100644 --- a/src/inline-assembly.md +++ b/src/inline-assembly.md @@ -11,12 +11,14 @@ Support for inline assembly is stable on the following architectures: - ARM - AArch64 - RISC-V +- LoongArch The compiler will emit an error if `asm!` is used on an unsupported target. ## Example ```rust +# #[cfg(target_arch = "x86_64")] { use std::arch::asm; // Multiply x by 6 using shifts and adds @@ -32,6 +34,7 @@ unsafe { ); } assert_eq!(x, 4 * 6); +# } ``` ## Syntax @@ -41,18 +44,17 @@ The following ABNF specifies the general syntax: ```text format_string := STRING_LITERAL / RAW_STRING_LITERAL dir_spec := "in" / "out" / "lateout" / "inout" / "inlateout" -reg_spec := / "" +reg_spec := / "\"" "\"" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" -reg_operand := dir_spec "(" reg_spec ")" operand_expr -operand := reg_operand +reg_operand := [ident "="] dir_spec "(" reg_spec ")" operand_expr clobber_abi := "clobber_abi(" *("," ) [","] ")" option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" / "raw" options := "options(" option *("," option) [","] ")" -asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," clobber_abi) *("," options) [","] ")" -global_asm := "global_asm!(" format_string *("," format_string) *("," [ident "="] operand) *("," options) [","] ")" +operand := reg_operand / clobber_abi / options +asm := "asm!(" format_string *("," format_string) *("," operand) [","] ")" +global_asm := "global_asm!(" format_string *("," format_string) *("," operand) [","] ")" ``` - ## Scope Inline assembly can be used in one of two ways. @@ -74,8 +76,7 @@ An `asm!` invocation may have one or more template string arguments; an `asm!` w The expected usage is for each template string argument to correspond to a line of assembly code. All template string arguments must appear before any other arguments. -As with format strings, named arguments must appear after positional arguments. -Explicit [register operands](#register-operands) must appear at the end of the operand list, after named arguments if any. +As with format strings, positional arguments must appear before named arguments and explicit [register operands](#register-operands). Explicit register operands cannot be used by placeholders in the template string. All other named and positional operands must appear at least once in the template string, otherwise a compiler error is generated. @@ -123,12 +124,17 @@ Several types of operands are supported: * `inlateout() ` / `inlateout() => ` - Identical to `inout` except that the register allocator can reuse a register allocated to an `in` (this can happen if the compiler knows the `in` has the same initial value as the `inlateout`). - You should only write to the register after all inputs are read, otherwise you may clobber an input. +* `sym ` + - `` must refer to a `fn` or `static`. + - A mangled symbol name referring to the item is substituted into the asm template string. + - The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc). + - `` is allowed to point to a `#[thread_local]` static, in which case the asm code can combine the symbol with relocations (e.g. `@plt`, `@TPOFF`) to read from thread-local data. Operand expressions are evaluated from left to right, just like function call arguments. After the `asm!` has executed, outputs are written to in left to right order. This is significant if two outputs point to the same place: that place will contain the value of the rightmost output. -Since `global_asm!` exists outside a function, it cannot use input/output operands. +Since `global_asm!` exists outside a function, it can only use `sym` operands. ## Register operands @@ -159,8 +165,10 @@ Here is the list of currently supported register classes: | x86 | `ymm_reg` | `ymm[0-7]` (x86) `ymm[0-15]` (x86-64) | `x` | | x86 | `zmm_reg` | `zmm[0-7]` (x86) `zmm[0-31]` (x86-64) | `v` | | x86 | `kreg` | `k[1-7]` | `Yk` | +| x86 | `kreg0` | `k0` | Only clobbers | | x86 | `x87_reg` | `st([0-7])` | Only clobbers | | x86 | `mmx_reg` | `mm[0-7]` | Only clobbers | +| x86-64 | `tmm_reg` | `tmm[0-7]` | Only clobbers | | AArch64 | `reg` | `x[0-30]` | `r` | | AArch64 | `vreg` | `v[0-31]` | `w` | | AArch64 | `vreg_low16` | `v[0-15]` | `x` | @@ -178,13 +186,15 @@ Here is the list of currently supported register classes: | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | | RISC-V | `vreg` | `v[0-31]` | Only clobbers | +| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch | `freg` | `$f[0-31]` | `f` | > **Notes**: > - On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. > > - On x86-64 the high byte registers (e.g. `ah`) are not available in the `reg_byte` register class. > -> - Some register classes are marked as "Only clobbers" which means that they cannot be used for inputs or outputs, only clobbers of the form `out("reg") _` or `lateout("reg") _`. +> - Some register classes are marked as "Only clobbers" which means that registers in these classes cannot be used for inputs or outputs, only clobbers of the form `out() _` or `lateout() _`. Each register class has constraints on which value types they can be used with. This is necessary because the way a value is loaded into a register depends on its type. @@ -203,8 +213,9 @@ The availability of supported types for a particular register class may depend o | x86 | `kreg` | `avx512bw` | `i32`, `i64` | | x86 | `mmx_reg` | N/A | Only clobbers | | x86 | `x87_reg` | N/A | Only clobbers | +| x86 | `tmm_reg` | N/A | Only clobbers | | AArch64 | `reg` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | -| AArch64 | `vreg` | `fp` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
    `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
    `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | +| AArch64 | `vreg` | `neon` | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`,
    `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`,
    `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` | | AArch64 | `preg` | N/A | Only clobbers | | ARM | `reg` | None | `i8`, `i16`, `i32`, `f32` | | ARM | `sreg` | `vfp2` | `i32`, `f32` | @@ -215,6 +226,8 @@ The availability of supported types for a particular register class may depend o | RISC-V | `freg` | `f` | `f32` | | RISC-V | `freg` | `d` | `f64` | | RISC-V | `vreg` | N/A | Only clobbers | +| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | +| LoongArch64 | `freg` | None | `f32`, `f64` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -276,16 +289,27 @@ Here is the list of all supported register aliases: | RISC-V | `f[10-17]` | `fa[0-7]` | | RISC-V | `f[18-27]` | `fs[2-11]` | | RISC-V | `f[28-31]` | `ft[8-11]` | +| LoongArch | `$r0` | `$zero` | +| LoongArch | `$r1` | `$ra` | +| LoongArch | `$r2` | `$tp` | +| LoongArch | `$r3` | `$sp` | +| LoongArch | `$r[4-11]` | `$a[0-7]` | +| LoongArch | `$r[12-20]` | `$t[0-8]` | +| LoongArch | `$r21` | | +| LoongArch | `$r22` | `$fp`, `$s9` | +| LoongArch | `$r[23-31]` | `$s[0-8]` | +| LoongArch | `$f[0-7]` | `$fa[0-7]` | +| LoongArch | `$f[8-23]` | `$ft[0-15]` | +| LoongArch | `$f[24-31]` | `$fs[0-7]` | Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | -| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | -| x86 | `k0` | This is a constant zero register which can't be modified. | +| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V), `$s8` (LoongArch) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | x86 | `ip` | This is the program counter, not a real register. | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | AArch64 | `x18` | This is an OS-reserved register on some AArch64 targets. | @@ -293,6 +317,9 @@ Some registers cannot be used for input or output operands: | ARM | `r9` | This is an OS-reserved register on some ARM targets. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | +| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | +| LoongArch | `$r2` or `$tp` | This is reserved for TLS. | +| LoongArch | `$r21` | This is reserved by the ABI. | The frame pointer and base pointer registers are reserved for internal use by LLVM. While `asm!` statements cannot explicitly specify the use of reserved registers, in some cases LLVM will allocate one of these reserved registers for `reg` operands. Assembly code making use of reserved registers should be careful since `reg` operands may use the same registers. @@ -339,6 +366,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | +| LoongArch | `reg` | None | `$r1` | None | +| LoongArch | `freg` | None | `$f0` | None | > **Notes**: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. @@ -356,7 +385,7 @@ If all references to an operand already have modifiers then the warning is suppr ## ABI clobbers The `clobber_abi` keyword can be used to apply a default set of clobbers to an `asm!` block. -This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then a `lateout("reg") _` is implicitly added to the operands list. +This will automatically insert the necessary clobber constraints as needed for calling a function with a particular calling convention: if the calling convention does not fully preserve the value of a register across a call then `lateout("...") _` is implicitly added to the operands list (where the `...` is replaced by the register's name). `clobber_abi` may be specified any number of times. It will insert a clobber for all unique registers in the union of all specified calling conventions. @@ -366,12 +395,13 @@ The following ABIs can be used with `clobber_abi`: | Architecture | ABI name | Clobbered registers | | ------------ | -------- | ------------------- | -| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | -| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | -| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[1-7]`, `st([0-7])` | +| x86-32 | `"C"`, `"system"`, `"efiapi"`, `"cdecl"`, `"stdcall"`, `"fastcall"` | `ax`, `cx`, `dx`, `xmm[0-7]`, `mm[0-7]`, `k[0-7]`, `st([0-7])` | +| x86-64 | `"C"`, `"system"` (on Windows), `"efiapi"`, `"win64"` | `ax`, `cx`, `dx`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[0-7]`, `st([0-7])`, `tmm[0-7]` | +| x86-64 | `"C"`, `"system"` (on non-Windows), `"sysv64"` | `ax`, `cx`, `dx`, `si`, `di`, `r[8-11]`, `xmm[0-31]`, `mm[0-7]`, `k[0-7]`, `st([0-7])`, `tmm[0-7]` | | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x18`\*, `x30`, `v[0-31]`, `p[0-15]`, `ffr` | | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | +| LoongArch | `"C"`, `"system"`, `"efiapi"` | `$r1`, `$r[4-20]`, `$f[0-23]` | > Notes: > - On AArch64 `x18` only included in the clobber list if it is not considered as a reserved register on the target. @@ -382,12 +412,15 @@ The list of clobbered registers for each ABI is updated in rustc as architecture Flags are used to further influence the behavior of the inline assembly block. Currently the following options are defined: -- `pure`: The `asm!` block has no side effects, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). +- `pure`: The `asm!` block has no side effects, must eventually return, and its outputs depend only on its direct inputs (i.e. the values themselves, not what they point to) or values read from memory (unless the `nomem` options is also set). This allows the compiler to execute the `asm!` block fewer times than specified in the program (e.g. by hoisting it out of a loop) or even eliminate it entirely if the outputs are not used. + The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted. - `nomem`: The `asm!` blocks does not read or write to any memory. This allows the compiler to cache the values of modified global variables in registers across the `asm!` block since it knows that they are not read or written to by the `asm!`. + The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences. - `readonly`: The `asm!` block does not write to any memory. This allows the compiler to cache the values of unmodified global variables in registers across the `asm!` block since it knows that they are not written to by the `asm!`. + The compiler also assumes that this `asm!` block does not perform any kind of synchronization with other threads, e.g. via fences. - `preserves_flags`: The `asm!` block does not modify the flags register (defined in the rules below). This allows the compiler to avoid recomputing the condition flags after the `asm!` block. - `noreturn`: The `asm!` block never returns, and its return type is defined as `!` (never). @@ -402,7 +435,6 @@ Currently the following options are defined: The compiler performs some additional checks on options: - The `nomem` and `readonly` options are mutually exclusive: it is a compile-time error to specify both. -- The `pure` option must be combined with either the `nomem` or `readonly` options, otherwise a compile-time error is emitted. - It is a compile-time error to specify `pure` on an asm block with no outputs or only discarded outputs (`_`). - It is a compile-time error to specify `noreturn` on an asm block with outputs. @@ -431,6 +463,7 @@ To avoid undefined behavior, these rules must be followed when using function-sc - The compiler cannot assume that the instructions in the asm are the ones that will actually end up executed. - This effectively means that the compiler must treat the `asm!` as a black box and only take the interface specification into account, not the instructions themselves. - Runtime code patching is allowed, via target-specific mechanisms. + - However there is no guarantee that each `asm!` directly corresponds to a single instance of instructions in the object file: the compiler is free to duplicate or deduplicate `asm!` blocks. - Unless the `nostack` option is set, asm code is allowed to use stack space below the stack pointer. - On entry to the asm block the stack pointer is guaranteed to be suitably aligned (according to the target ABI) for a function call. - You are responsible for making sure you don't overflow the stack (e.g. use stack probing to ensure you hit a guard page). @@ -459,6 +492,8 @@ To avoid undefined behavior, these rules must be followed when using function-sc - RISC-V - Floating-point exception flags in `fcsr` (`fflags`). - Vector extension state (`vtype`, `vl`, `vcsr`). + - LoongArch + - Floating-point condition flags in `$fcc[0-7]`. - On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit. - Behavior is undefined if the direction flag is set on exiting an asm block. - On x86, the x87 floating-point register stack must remain unchanged unless all of the `st([0-7])` registers have been marked as clobbered with `out("st(0)") _, out("st(1)") _, ...`. @@ -479,6 +514,29 @@ To avoid undefined behavior, these rules must be followed when using function-sc > **Note**: As a general rule, the flags covered by `preserves_flags` are those which are *not* preserved when performing a function call. +### Correctness and Validity + +In addition to all of the previous rules, the string argument to `asm!` must ultimately become--- +after all other arguments are evaluated, formatting is performed, and operands are translated--- +assembly that is both syntactically correct and semantically valid for the target architecture. +The formatting rules allow the compiler to generate assembly with correct syntax. +Rules concerning operands permit valid translation of Rust operands into and out of `asm!`. +Adherence to these rules is necessary, but not sufficient, for the final expanded assembly to be +both correct and valid. For instance: + +- arguments may be placed in positions which are syntactically incorrect after formatting +- an instruction may be correctly written, but given architecturally invalid operands +- an architecturally unspecified instruction may be assembled into unspecified code +- a set of instructions, each correct and valid, may cause undefined behavior if placed in immediate succession + +As a result, these rules are _non-exhaustive_. The compiler is not required to check the +correctness and validity of the initial string nor the final assembly that is generated. +The assembler may check for correctness and validity but is not required to do so. +When using `asm!`, a typographical error may be sufficient to make a program unsound, +and the rules for assembly may include thousands of pages of architectural reference manuals. +Programmers should exercise appropriate care, as invoking this `unsafe` capability comes with +assuming the responsibility of not violating rules of both the compiler or the architecture. + ### Directives Support Inline assembly supports a subset of the directives supported by both GNU AS and LLVM's internal assembler, given as follows. @@ -492,12 +550,9 @@ The following directives are guaranteed to be supported by the assembler: - `.4byte` - `.8byte` - `.align` +- `.alt_entry` - `.ascii` - `.asciz` -- `.alt_entry` -- `.balign` -- `.balignl` -- `.balignw` - `.balign` - `.balignl` - `.balignw` @@ -513,17 +568,18 @@ The following directives are guaranteed to be supported by the assembler: - `.eqv` - `.fill` - `.float` -- `.globl` - `.global` -- `.lcomm` +- `.globl` - `.inst` +- `.insn` +- `.lcomm` - `.long` - `.octa` - `.option` -- `.private_extern` - `.p2align` -- `.pushsection` - `.popsection` +- `.private_extern` +- `.pushsection` - `.quad` - `.scl` - `.section` diff --git a/src/input-format.md b/src/input-format.md index 678902c..8d921bf 100644 --- a/src/input-format.md +++ b/src/input-format.md @@ -1,3 +1,55 @@ # Input format -Rust input is interpreted as a sequence of Unicode code points encoded in UTF-8. +This chapter describes how a source file is interpreted as a sequence of tokens. + +See [Crates and source files] for a description of how programs are organised into files. + +## Source encoding + +Each source file is interpreted as a sequence of Unicode characters encoded in UTF-8. +It is an error if the file is not valid UTF-8. + +## Byte order mark removal + +If the first character in the sequence is `U+FEFF` ([BYTE ORDER MARK]), it is removed. + +## CRLF normalization + +Each pair of characters `U+000D` (CR) immediately followed by `U+000A` (LF) is replaced by a single `U+000A` (LF). + +Other occurrences of the character `U+000D` (CR) are left in place (they are treated as [whitespace]). + +## Shebang removal + +If the remaining sequence begins with the characters `#!`, the characters up to and including the first `U+000A` (LF) are removed from the sequence. + +For example, the first line of the following file would be ignored: + + +```rust,ignore +#!/usr/bin/env rustx + +fn main() { + println!("Hello!"); +} +``` + +As an exception, if the `#!` characters are followed (ignoring intervening [comments] or [whitespace]) by a `[` token, nothing is removed. +This prevents an [inner attribute] at the start of a source file being removed. + +> **Note**: The standard library [`include!`] macro applies byte order mark removal, CRLF normalization, and shebang removal to the file it reads. The [`include_str!`] and [`include_bytes!`] macros do not. + +## Tokenization + +The resulting sequence of characters is then converted into tokens as described in the remainder of this chapter. + + +[`include!`]: ../std/macro.include.md +[`include_bytes!`]: ../std/macro.include_bytes.md +[`include_str!`]: ../std/macro.include_str.md +[inner attribute]: attributes.md +[BYTE ORDER MARK]: https://en.wikipedia.org/wiki/Byte_order_mark#UTF-8 +[comments]: comments.md +[Crates and source files]: crates-and-source-files.md +[_shebang_]: https://en.wikipedia.org/wiki/Shebang_(Unix) +[whitespace]: whitespace.md diff --git a/src/interior-mutability.md b/src/interior-mutability.md index e786d56..9146007 100644 --- a/src/interior-mutability.md +++ b/src/interior-mutability.md @@ -6,7 +6,7 @@ mutability if its internal state can be changed through a [shared reference] to it. This goes against the usual [requirement][ub] that the value pointed to by a shared reference is not mutated. -[`std::cell::UnsafeCell`] type is the only allowed way in Rust to disable +[`std::cell::UnsafeCell`] type is the only allowed way to disable this requirement. When `UnsafeCell` is immutably aliased, it is still safe to mutate, or obtain a mutable reference to, the `T` it contains. As with all other types, it is undefined behavior to have multiple `&mut UnsafeCell` diff --git a/src/items.md b/src/items.md index addbe0e..00639ac 100644 --- a/src/items.md +++ b/src/items.md @@ -53,15 +53,14 @@ There are several kinds of items: * [implementations] * [`extern` blocks] -Some items form an implicit scope for the declaration of sub-items. In other -words, within a function or module, declarations of items can (in many cases) -be mixed with the statements, control blocks, and similar artifacts that -otherwise compose the item body. The meaning of these scoped items is the same -as if the item was declared outside the scope — it is still a static item -— except that the item's *path name* within the module namespace is -qualified by the name of the enclosing item, or is private to the enclosing -item (in the case of functions). The grammar specifies the exact locations in -which sub-item declarations may appear. +Items may be declared in the [root of the crate], a [module][modules], or a [block expression]. +A subset of items, called [associated items], may be declared in [traits] and [implementations]. +A subset of items, called external items, may be declared in [`extern` blocks]. + +Items may be defined in any order, with the exception of [`macro_rules`] which has its own scoping behavior. +[Name resolution] of item names allows items to be defined before or after where the item is referred to in the module or block. + +See [item scopes] for information on the scoping rules of items. [_ConstantItem_]: items/constant-items.md [_Enumeration_]: items/enumerations.md @@ -82,15 +81,23 @@ which sub-item declarations may appear. [_Visibility_]: visibility-and-privacy.md [`extern crate` declarations]: items/extern-crates.md [`extern` blocks]: items/external-blocks.md +[`macro_rules`]: macros-by-example.md [`use` declarations]: items/use-declarations.md +[associated items]: items/associated-items.md +[block expression]: expressions/block-expr.md [constant items]: items/constant-items.md [enumeration definitions]: items/enumerations.md [function definitions]: items/functions.md [implementations]: items/implementations.md +[item scopes]: names/scopes.md#item-scopes [modules]: items/modules.md +[name resolution]: names/name-resolution.md [paths]: paths.md +[root of the crate]: crates-and-source-files.md +[statement]: statements.md [static items]: items/static-items.md [struct definitions]: items/structs.md [trait definitions]: items/traits.md +[traits]: items/traits.md [type definitions]: items/type-aliases.md [union definitions]: items/unions.md diff --git a/src/items/associated-items.md b/src/items/associated-items.md index f5dc31a..2401127 100644 --- a/src/items/associated-items.md +++ b/src/items/associated-items.md @@ -205,22 +205,49 @@ types cannot be defined in [inherent implementations] nor can they be given a default implementation in traits. An *associated type declaration* declares a signature for associated type -definitions. It is written as `type`, then an [identifier], and -finally an optional list of trait bounds. +definitions. It is written in one of the following forms, where `Assoc` is the +name of the associated type, `Params` is a comma-separated list of type, +lifetime or const parameters, `Bounds` is a plus-separated list of trait bounds +that the associated type must meet, and `WhereBounds` is a comma-separated list +of bounds that the parameters must meet: + + +```rust,ignore +type Assoc; +type Assoc: Bounds; +type Assoc; +type Assoc: Bounds; +type Assoc where WhereBounds; +type Assoc: Bounds where WhereBounds; +``` The identifier is the name of the declared type alias. The optional trait bounds must be fulfilled by the implementations of the type alias. There is an implicit [`Sized`] bound on associated types that can be relaxed using the special `?Sized` bound. -An *associated type definition* defines a type alias on another type. It is -written as `type`, then an [identifier], then an `=`, and finally a [type]. +An *associated type definition* defines a type alias for the implementation +of a trait on a type. They are written similarly to an *associated type declaration*, +but cannot contain `Bounds`, but instead must contain a `Type`: + + +```rust,ignore +type Assoc = Type; +type Assoc = Type; // the type `Type` here may reference `Params` +type Assoc = Type where WhereBounds; +type Assoc where WhereBounds = Type; // deprecated, prefer the form above +``` If a type `Item` has an associated type `Assoc` from a trait `Trait`, then `::Assoc` is a type that is an alias of the type specified in the associated type definition. Furthermore, if `Item` is a type parameter, then `Item::Assoc` can be used in type parameters. -Associated types must not include [generic parameters] or [where clauses]. +Associated types may include [generic parameters] and [where clauses]; these are +often referred to as *generic associated types*, or *GATs*. If the type `Thing` +has an associated type `Item` from a trait `Trait` with the generics `<'a>` , the +type can be named like `::Item<'x>`, where `'x` is some lifetime +in scope. In this case, `'x` will be used wherever `'a` appears in the associated +type definitions on impls. ```rust trait AssociatedType { @@ -249,6 +276,37 @@ fn main() { } ``` +An example of associated types with generics and where clauses: + +```rust +struct ArrayLender<'a, T>(&'a mut [T; 16]); + +trait Lend { + // Generic associated type declaration + type Lender<'a> where Self: 'a; + fn lend<'a>(&'a mut self) -> Self::Lender<'a>; +} + +impl Lend for [T; 16] { + // Generic associated type definition + type Lender<'a> = ArrayLender<'a, T> where Self: 'a; + + fn lend<'a>(&'a mut self) -> Self::Lender<'a> { + ArrayLender(self) + } +} + +fn borrow<'a, T: Lend>(array: &'a mut T) -> ::Lender<'a> { + array.lend() +} + + +fn main() { + let mut array = [0usize; 16]; + let lender = borrow(&mut array); +} +``` + ### Associated Types Container Example Consider the following example of a `Container` trait. Notice that the type is @@ -279,6 +337,83 @@ impl Container for Vec { } ``` +### Relationship between `Bounds` and `WhereBounds` + +In this example: + +```rust +# use std::fmt::Debug; +trait Example { + type Output: Ord where T: Debug; +} +``` + +Given a reference to the associated type like `::Output`, the associated type itself must be `Ord`, and the type `Y` must be `Debug`. + +### Required where clauses on generic associated types + +Generic associated type declarations on traits currently may require a list of +where clauses, dependent on functions in the trait and how the GAT is used. These +rules may be loosened in the future; updates can be found [on the generic +associated types initiative repository](https://rust-lang.github.io/generic-associated-types-initiative/explainer/required_bounds.html). + +In a few words, these where clauses are required in order to maximize the allowed +definitions of the associated type in impls. To do this, any clauses that *can be +proven to hold* on functions (using the parameters of the function or trait) +where a GAT appears as an input or output must also be written on the GAT itself. + +```rust +trait LendingIterator { + type Item<'x> where Self: 'x; + fn next<'a>(&'a mut self) -> Self::Item<'a>; +} +``` + +In the above, on the `next` function, we can prove that `Self: 'a`, because of +the implied bounds from `&'a mut self`; therefore, we must write the equivalent +bound on the GAT itself: `where Self: 'x`. + +When there are multiple functions in a trait that use the GAT, then the +*intersection* of the bounds from the different functions are used, rather than +the union. + +```rust +trait Check { + type Checker<'x>; + fn create_checker<'a>(item: &'a T) -> Self::Checker<'a>; + fn do_check(checker: Self::Checker<'_>); +} +``` + +In this example, no bounds are required on the `type Checker<'a>;`. While we +know that `T: 'a` on `create_checker`, we do not know that on `do_check`. However, +if `do_check` was commented out, then the `where T: 'x` bound would be required +on `Checker`. + +The bounds on associated types also propagate required where clauses. + +```rust +trait Iterable { + type Item<'a> where Self: 'a; + type Iterator<'a>: Iterator> where Self: 'a; + fn iter<'a>(&'a self) -> Self::Iterator<'a>; +} +``` + +Here, `where Self: 'a` is required on `Item` because of `iter`. However, `Item` +is used in the bounds of `Iterator`, the `where Self: 'a` clause is also required +there. + +Finally, any explicit uses of `'static` on GATs in the trait do not count towards +the required bounds. + +```rust +trait StaticReturn { + type Y<'a>; + fn foo(&self) -> Self::Y<'static>; +} +``` + ## Associated Constants *Associated constants* are [constants] associated with a type. diff --git a/src/items/constant-items.md b/src/items/constant-items.md index bf31593..9fb2185 100644 --- a/src/items/constant-items.md +++ b/src/items/constant-items.md @@ -11,12 +11,14 @@ context when used. This includes usage of constants from external crates, and non-[`Copy`] types. References to the same constant are not necessarily guaranteed to refer to the same memory address. +The constant declaration defines the constant value in the [value namespace] of the module or block where it is located. + Constants must be explicitly typed. The type must have a `'static` lifetime: any references in the initializer must have `'static` lifetimes. Constants may refer to the address of other constants, in which case the -address will have elided lifetimes where applicable, otherwise – in most cases -– defaulting to the `static` lifetime. (See [static lifetime +address will have elided lifetimes where applicable, otherwise -- in most cases +-- defaulting to the `static` lifetime. (See [static lifetime elision].) The compiler is, however, still at liberty to translate the constant many times, so the address referred to may not be stable. @@ -89,6 +91,22 @@ m!(const _: () = ();); // const _: () = (); ``` +## Evaluation + +[Free][free] constants are always [evaluated][const_eval] at compile-time to surface +panics. This happens even within an unused function: + +```rust,compile_fail +// Compile-time panic +const PANIC: () = std::unimplemented!(); + +fn unused_generic_function() { + // A failing compile-time assertion + const _: () = assert!(usize::BITS == 0); +} +``` + +[const_eval]: ../const_eval.md [associated constant]: ../items/associated-items.md#associated-constants [constant value]: ../const_eval.md#constant-expressions [free]: ../glossary.md#free-item @@ -99,3 +117,4 @@ m!(const _: () = ();); [_Type_]: ../types.md#type-expressions [_Expression_]: ../expressions.md [`Copy`]: ../special-types-and-traits.md#copy +[value namespace]: ../names/namespaces.md diff --git a/src/items/enumerations.md b/src/items/enumerations.md index 28d3ba8..5f00846 100644 --- a/src/items/enumerations.md +++ b/src/items/enumerations.md @@ -13,8 +13,8 @@ > > _EnumItem_ :\ >    _OuterAttribute_\* [_Visibility_]?\ ->    [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_ -> | _EnumItemDiscriminant_ )? +>    [IDENTIFIER] ( _EnumItemTuple_ | _EnumItemStruct_ )? +> _EnumItemDiscriminant_? > > _EnumItemTuple_ :\ >    `(` [_TupleFields_]? `)` @@ -30,6 +30,7 @@ nominal [enumerated type] as well as a set of *constructors*, that can be used to create or pattern-match values of the corresponding enumerated type. Enumerations are declared with the keyword `enum`. +The `enum` declaration defines the enumeration type in the [type namespace] of the module or block where it is located. An example of an `enum` item and its use: @@ -56,22 +57,95 @@ a = Animal::Cat { name: "Spotty".to_string(), weight: 2.7 }; ``` In this example, `Cat` is a _struct-like enum variant_, whereas `Dog` is simply -called an enum variant. Each enum instance has a _discriminant_ which is an -integer associated to it that is used to determine which variant it holds. An -opaque reference to this discriminant can be obtained with the -[`mem::discriminant`] function. +called an enum variant. -## Custom Discriminant Values for Fieldless Enumerations +An enum where no constructors contain fields are called a +*field-less enum*. For example, this is a fieldless enum: -If there is no data attached to *any* of the variants of an enumeration, -then the discriminant can be directly chosen and accessed. +```rust +enum Fieldless { + Tuple(), + Struct{}, + Unit, +} +``` + +If a field-less enum only contains unit variants, the enum is called an +*unit-only enum*. For example: + +```rust +enum Enum { + Foo = 3, + Bar = 2, + Baz = 1, +} +``` + +Variant constructors are similar to [struct] definitions, and can be referenced by a path from the enumeration name, including in [use declarations]. +Each variant defines its type in the [type namespace], though that type cannot be used as a type specifier. +Tuple-like and unit-like variants also define a constructor in the [value namespace]. + +A struct-like variant can be instantiated with a [struct expression]. +A tuple-like variant can be instantiated with a [call expression] or a [struct expression]. +A unit-like variant can be instantiated with a [path expression] or a [struct expression]. +For example: + +```rust +enum Examples { + UnitLike, + TupleLike(i32), + StructLike { value: i32 }, +} + +use Examples::*; // Creates aliases to all variants. +let x = UnitLike; // Path expression of the const item. +let x = UnitLike {}; // Struct expression. +let y = TupleLike(123); // Call expression. +let y = TupleLike { 0: 123 }; // Struct expression using integer field names. +let z = StructLike { value: 123 }; // Struct expression. +``` + + +## Discriminants + +Each enum instance has a _discriminant_: an integer logically associated to it +that is used to determine which variant it holds. + +Under the [default representation], the discriminant is interpreted as +an `isize` value. However, the compiler is allowed to use a smaller type (or +another means of distinguishing variants) in its actual memory layout. + +### Assigning discriminant values -These enumerations can be cast to integer types with the `as` operator by a -[numeric cast]. The enumeration can optionally specify which integer each -discriminant gets by following the variant name with `=` followed by a [constant -expression]. If the first variant in the declaration is unspecified, then it is -set to zero. For every other unspecified discriminant, it is set to one higher -than the previous variant in the declaration. +#### Explicit discriminants + +In two circumstances, the discriminant of a variant may be explicitly set by +following the variant name with `=` and a [constant expression]: + + +1. if the enumeration is "[unit-only]". + + +2. if a [primitive representation] is used. For example: + + ```rust + #[repr(u8)] + enum Enum { + Unit = 3, + Tuple(u16), + Struct { + a: u8, + b: u16, + } = 1, + } + ``` + +#### Implicit discriminants + +If a discriminant for a variant is not specified, then it is set to one higher +than the discriminant of the previous variant in the declaration. If the +discriminant of the first variant in the declaration is unspecified, then +it is set to zero. ```rust enum Foo { @@ -84,10 +158,7 @@ let baz_discriminant = Foo::Baz as u32; assert_eq!(baz_discriminant, 123); ``` -Under the [default representation], the specified discriminant is interpreted as -an `isize` value although the compiler is allowed to use a smaller type in the -actual memory layout. The size and thus acceptable values can be changed by -using a [primitive representation] or the [`C` representation]. +#### Restrictions It is an error when two variants share the same discriminant. @@ -122,7 +193,89 @@ enum OverflowingDiscriminantError2 { } ``` -## Zero-variant Enums +### Accessing discriminant + +#### Via `mem::discriminant` + +[`mem::discriminant`] returns an opaque reference to the discriminant of +an enum value which can be compared. This cannot be used to get the value +of the discriminant. + +#### Casting + +If an enumeration is [unit-only] (with no tuple and struct variants), then its +discriminant can be directly accessed with a [numeric cast]; e.g.: + +```rust +enum Enum { + Foo, + Bar, + Baz, +} + +assert_eq!(0, Enum::Foo as isize); +assert_eq!(1, Enum::Bar as isize); +assert_eq!(2, Enum::Baz as isize); +``` + +[Field-less enums] can be casted if they do not have explicit discriminants, or where only unit variants are explicit. + +```rust +enum Fieldless { + Tuple(), + Struct{}, + Unit, +} + +assert_eq!(0, Fieldless::Tuple() as isize); +assert_eq!(1, Fieldless::Struct{} as isize); +assert_eq!(2, Fieldless::Unit as isize); + +#[repr(u8)] +enum FieldlessWithDiscrimants { + First = 10, + Tuple(), + Second = 20, + Struct{}, + Unit, +} + +assert_eq!(10, FieldlessWithDiscrimants::First as u8); +assert_eq!(11, FieldlessWithDiscrimants::Tuple() as u8); +assert_eq!(20, FieldlessWithDiscrimants::Second as u8); +assert_eq!(21, FieldlessWithDiscrimants::Struct{} as u8); +assert_eq!(22, FieldlessWithDiscrimants::Unit as u8); +``` + +#### Pointer casting + +If the enumeration specifies a [primitive representation], then the +discriminant may be reliably accessed via unsafe pointer casting: + +```rust +#[repr(u8)] +enum Enum { + Unit, + Tuple(bool), + Struct{a: bool}, +} + +impl Enum { + fn discriminant(&self) -> u8 { + unsafe { *(self as *const Self as *const u8) } + } +} + +let unit_like = Enum::Unit; +let tuple_like = Enum::Tuple(true); +let struct_like = Enum::Struct{a: false}; + +assert_eq!(0, unit_like.discriminant()); +assert_eq!(1, tuple_like.discriminant()); +assert_eq!(2, struct_like.discriminant()); +``` + +## Zero-variant enums Enums with zero variants are known as *zero-variant enums*. As they have no valid values, they cannot be instantiated. @@ -171,18 +324,27 @@ enum E { } ``` -[IDENTIFIER]: ../identifiers.md -[_GenericParams_]: generics.md -[_WhereClause_]: generics.md#where-clauses [_Expression_]: ../expressions.md -[_TupleFields_]: structs.md +[_GenericParams_]: generics.md [_StructFields_]: structs.md +[_TupleFields_]: structs.md [_Visibility_]: ../visibility-and-privacy.md -[enumerated type]: ../types/enum.md +[_WhereClause_]: generics.md#where-clauses +[`C` representation]: ../type-layout.md#the-c-representation [`mem::discriminant`]: ../../std/mem/fn.discriminant.html -[never type]: ../types/never.md -[numeric cast]: ../expressions/operator-expr.md#semantics +[call expression]: ../expressions/call-expr.md [constant expression]: ../const_eval.md#constant-expressions [default representation]: ../type-layout.md#the-default-representation +[enumerated type]: ../types/enum.md +[Field-less enums]: #field-less-enum +[IDENTIFIER]: ../identifiers.md +[never type]: ../types/never.md +[numeric cast]: ../expressions/operator-expr.md#semantics +[path expression]: ../expressions/path-expr.md [primitive representation]: ../type-layout.md#primitive-representations -[`C` representation]: ../type-layout.md#the-c-representation +[struct expression]: ../expressions/struct-expr.md +[struct]: structs.md +[type namespace]: ../names/namespaces.md +[unit-only]: #unit-only-enum +[use declarations]: use-declarations.md +[value namespace]: ../names/namespaces.md diff --git a/src/items/extern-crates.md b/src/items/extern-crates.md index f4dc735..523e972 100644 --- a/src/items/extern-crates.md +++ b/src/items/extern-crates.md @@ -11,18 +11,16 @@ >    `as` ( [IDENTIFIER] | `_` ) An _`extern crate` declaration_ specifies a dependency on an external crate. -The external crate is then bound into the declaring scope as the [identifier] -provided in the `extern crate` declaration. Additionally, if the `extern -crate` appears in the crate root, then the crate name is also added to the -[extern prelude], making it automatically in scope in all modules. The `as` -clause can be used to bind the imported crate to a different name. +The external crate is then bound into the declaring scope as the given [identifier] in the [type namespace]. +Additionally, if the `extern crate` appears in the crate root, then the crate name is also added to the [extern prelude], making it automatically in scope in all modules. +The `as` clause can be used to bind the imported crate to a different name. The external crate is resolved to a specific `soname` at compile time, and a runtime linkage requirement to that `soname` is passed to the linker for loading at runtime. The `soname` is resolved at compile time by scanning the -compiler's library path and matching the optional `crateid` provided against -the `crateid` attributes that were declared on the external crate when it was -compiled. If no `crateid` is provided, a default `name` attribute is assumed, +compiler's library path and matching the optional `crate_name` provided against +the [`crate_name` attributes] that were declared on the external crate when it was +compiled. If no `crate_name` is provided, a default `name` attribute is assumed, equal to the [identifier] given in the `extern crate` declaration. The `self` crate may be imported which creates a binding to the current crate. @@ -52,11 +50,6 @@ Here is an example: extern crate hello_world; // hyphen replaced with an underscore ``` -## Extern Prelude - -This section has been moved to [Preludes — Extern Prelude](../names/preludes.md#extern-prelude). - - ## Underscore Imports An external crate dependency can be declared without binding its name in scope @@ -78,6 +71,8 @@ crate to access only its macros. [`macro_use` attribute]: ../macros-by-example.md#the-macro_use-attribute [extern prelude]: ../names/preludes.md#extern-prelude [`macro_use` prelude]: ../names/preludes.md#macro_use-prelude +[`crate_name` attributes]: ../crates-and-source-files.md#the-crate_name-attribute +[type namespace]: ../names/namespaces.md