mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-24 12:54:00 +00:00
Auto merge of #74408 - Manishearth:rollup-9gxn4od, r=Manishearth
Rollup of 21 pull requests Successful merges: - #73566 (Don't run `everybody_loops` for rustdoc; instead ignore resolution errors) - #73771 (Don't pollute docs/suggestions with libstd deps) - #73794 (Small cleanup for E0705 explanation) - #73807 (rustdoc: glue tokens before highlighting) - #73835 (Clean up E0710 explanation) - #73926 (Ignoring test case: [codegen] repr-transparent-aggregates-1.rs for aarch64) - #73981 (Remove some `ignore-stage1` annotations.) - #73998 (add regression test for #61216) - #74140 (Make hir ProjectionKind more precise) - #74148 (Move #[doc(alias)] check in rustc) - #74159 (forbid generic params in the type of const params) - #74171 (Fix 44056 test with debug on macos.) - #74221 (Don't panic if the lhs of a div by zero is not statically known) - #74325 (Focus on the current file in the source file sidebar) - #74359 (rustdoc: Rename internal API fns to `into_string`) - #74370 (Reintroduce spotlight / "important traits" feature) - #74390 (Fix typo in std::mem::transmute documentation) - #74391 (BtreeMap: superficially refactor root access) - #74392 (const generics triage) - #74397 (Fix typo in the latest release note) - #74406 (Set shell for github actions CI) Failed merges: r? @ghost
This commit is contained in:
commit
5c9e5df3a0
77
.github/workflows/ci.yml
vendored
77
.github/workflows/ci.yml
vendored
@ -66,59 +66,77 @@ jobs:
|
||||
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
|
||||
- name: add extra environment variables
|
||||
run: src/ci/scripts/setup-environment.sh
|
||||
shell: bash
|
||||
env:
|
||||
EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: decide whether to skip this job
|
||||
run: src/ci/scripts/should-skip-this.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: collect CPU statistics
|
||||
run: src/ci/scripts/collect-cpu-stats.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install clang
|
||||
run: src/ci/scripts/install-clang.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install WIX
|
||||
run: src/ci/scripts/install-wix.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure the build happens on a partition with enough space
|
||||
run: src/ci/scripts/symlink-build-dir.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install ninja
|
||||
run: src/ci/scripts/install-ninja.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: enable ipv6 on Docker
|
||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure line endings are correct
|
||||
run: src/ci/scripts/verify-line-endings.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: run the build
|
||||
run: src/ci/scripts/run-build-from-ci.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -126,6 +144,7 @@ jobs:
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -166,59 +185,77 @@ jobs:
|
||||
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
|
||||
- name: add extra environment variables
|
||||
run: src/ci/scripts/setup-environment.sh
|
||||
shell: bash
|
||||
env:
|
||||
EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: decide whether to skip this job
|
||||
run: src/ci/scripts/should-skip-this.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: collect CPU statistics
|
||||
run: src/ci/scripts/collect-cpu-stats.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install clang
|
||||
run: src/ci/scripts/install-clang.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install WIX
|
||||
run: src/ci/scripts/install-wix.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure the build happens on a partition with enough space
|
||||
run: src/ci/scripts/symlink-build-dir.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install ninja
|
||||
run: src/ci/scripts/install-ninja.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: enable ipv6 on Docker
|
||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure line endings are correct
|
||||
run: src/ci/scripts/verify-line-endings.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: run the build
|
||||
run: src/ci/scripts/run-build-from-ci.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -226,6 +263,7 @@ jobs:
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -484,59 +522,77 @@ jobs:
|
||||
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
|
||||
- name: add extra environment variables
|
||||
run: src/ci/scripts/setup-environment.sh
|
||||
shell: bash
|
||||
env:
|
||||
EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: decide whether to skip this job
|
||||
run: src/ci/scripts/should-skip-this.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: collect CPU statistics
|
||||
run: src/ci/scripts/collect-cpu-stats.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install clang
|
||||
run: src/ci/scripts/install-clang.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install WIX
|
||||
run: src/ci/scripts/install-wix.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure the build happens on a partition with enough space
|
||||
run: src/ci/scripts/symlink-build-dir.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install ninja
|
||||
run: src/ci/scripts/install-ninja.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: enable ipv6 on Docker
|
||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure line endings are correct
|
||||
run: src/ci/scripts/verify-line-endings.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: run the build
|
||||
run: src/ci/scripts/run-build-from-ci.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -544,6 +600,7 @@ jobs:
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -610,59 +667,77 @@ jobs:
|
||||
if: "success() && !env.SKIP_JOB && github.ref != 'refs/heads/try'"
|
||||
- name: add extra environment variables
|
||||
run: src/ci/scripts/setup-environment.sh
|
||||
shell: bash
|
||||
env:
|
||||
EXTRA_VARIABLES: "${{ toJson(matrix.env) }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: decide whether to skip this job
|
||||
run: src/ci/scripts/should-skip-this.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: collect CPU statistics
|
||||
run: src/ci/scripts/collect-cpu-stats.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install clang
|
||||
run: src/ci/scripts/install-clang.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install WIX
|
||||
run: src/ci/scripts/install-wix.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure the build happens on a partition with enough space
|
||||
run: src/ci/scripts/symlink-build-dir.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: install ninja
|
||||
run: src/ci/scripts/install-ninja.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: enable ipv6 on Docker
|
||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: ensure line endings are correct
|
||||
run: src/ci/scripts/verify-line-endings.sh
|
||||
shell: bash
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: run the build
|
||||
run: src/ci/scripts/run-build-from-ci.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.CACHES_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -670,6 +745,7 @@ jobs:
|
||||
if: success() && !env.SKIP_JOB
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: "${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}"
|
||||
AWS_SECRET_ACCESS_KEY: "${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}"
|
||||
@ -694,6 +770,7 @@ jobs:
|
||||
fetch-depth: 2
|
||||
- name: publish toolstate
|
||||
run: src/ci/publish_toolstate.sh
|
||||
shell: bash
|
||||
env:
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: "${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}"
|
||||
if: success() && !env.SKIP_JOB
|
||||
|
@ -47,7 +47,7 @@ Libraries
|
||||
// Prints "abcdefghijklmnopqrstuvwxyz"
|
||||
```
|
||||
- [`OsString` now implements `FromStr`.][71662]
|
||||
- [The `saturating_neg` method as been added to all signed integer primitive
|
||||
- [The `saturating_neg` method has been added to all signed integer primitive
|
||||
types, and the `saturating_abs` method has been added for all integer
|
||||
primitive types.][71886]
|
||||
- [`Arc<T>`, `Rc<T>` now implement `From<Cow<'_, T>>`, and `Box` now
|
||||
|
@ -95,6 +95,7 @@ x--expand-yaml-anchors--remove:
|
||||
|
||||
- name: add extra environment variables
|
||||
run: src/ci/scripts/setup-environment.sh
|
||||
shell: bash
|
||||
env:
|
||||
# Since it's not possible to merge `${{ matrix.env }}` with the other
|
||||
# variables in `job.<name>.env`, the variables defined in the matrix
|
||||
@ -105,54 +106,67 @@ x--expand-yaml-anchors--remove:
|
||||
|
||||
- name: decide whether to skip this job
|
||||
run: src/ci/scripts/should-skip-this.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: collect CPU statistics
|
||||
run: src/ci/scripts/collect-cpu-stats.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: show the current environment
|
||||
run: src/ci/scripts/dump-environment.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install awscli
|
||||
run: src/ci/scripts/install-awscli.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install sccache
|
||||
run: src/ci/scripts/install-sccache.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install clang
|
||||
run: src/ci/scripts/install-clang.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install WIX
|
||||
run: src/ci/scripts/install-wix.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: ensure the build happens on a partition with enough space
|
||||
run: src/ci/scripts/symlink-build-dir.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install MSYS2
|
||||
run: src/ci/scripts/install-msys2.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install MinGW
|
||||
run: src/ci/scripts/install-mingw.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: install ninja
|
||||
run: src/ci/scripts/install-ninja.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: enable ipv6 on Docker
|
||||
run: src/ci/scripts/enable-docker-ipv6.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
# Disable automatic line ending conversion (again). On Windows, when we're
|
||||
@ -162,18 +176,22 @@ x--expand-yaml-anchors--remove:
|
||||
# appropriate line endings.
|
||||
- name: disable git crlf conversion
|
||||
run: src/ci/scripts/disable-git-crlf-conversion.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: checkout submodules
|
||||
run: src/ci/scripts/checkout-submodules.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: ensure line endings are correct
|
||||
run: src/ci/scripts/verify-line-endings.sh
|
||||
shell: bash
|
||||
<<: *step
|
||||
|
||||
- name: run the build
|
||||
run: src/ci/scripts/run-build-from-ci.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.CACHES_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.CACHES_AWS_ACCESS_KEY_ID)] }}
|
||||
@ -182,6 +200,7 @@ x--expand-yaml-anchors--remove:
|
||||
|
||||
- name: upload artifacts to S3
|
||||
run: src/ci/scripts/upload-artifacts.sh
|
||||
shell: bash
|
||||
env:
|
||||
AWS_ACCESS_KEY_ID: ${{ env.ARTIFACTS_AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets[format('AWS_SECRET_ACCESS_KEY_{0}', env.ARTIFACTS_AWS_ACCESS_KEY_ID)] }}
|
||||
@ -620,6 +639,7 @@ jobs:
|
||||
|
||||
- name: publish toolstate
|
||||
run: src/ci/publish_toolstate.sh
|
||||
shell: bash
|
||||
env:
|
||||
TOOLSTATE_REPO_ACCESS_TOKEN: ${{ secrets.TOOLSTATE_REPO_ACCESS_TOKEN }}
|
||||
<<: *step
|
||||
|
@ -150,6 +150,27 @@ Book][unstable-doc-cfg] and [its tracking issue][issue-doc-cfg].
|
||||
[unstable-doc-cfg]: ../unstable-book/language-features/doc-cfg.html
|
||||
[issue-doc-cfg]: https://github.com/rust-lang/rust/issues/43781
|
||||
|
||||
### Adding your trait to the "Important Traits" dialog
|
||||
|
||||
Rustdoc keeps a list of a few traits that are believed to be "fundamental" to a given type when
|
||||
implemented on it. These traits are intended to be the primary interface for their types, and are
|
||||
often the only thing available to be documented on their types. For this reason, Rustdoc will track
|
||||
when a given type implements one of these traits and call special attention to it when a function
|
||||
returns one of these types. This is the "Important Traits" dialog, visible as a circle-i button next
|
||||
to the function, which, when clicked, shows the dialog.
|
||||
|
||||
In the standard library, the traits that qualify for inclusion are `Iterator`, `io::Read`, and
|
||||
`io::Write`. However, rather than being implemented as a hard-coded list, these traits have a
|
||||
special marker attribute on them: `#[doc(spotlight)]`. This means that you could apply this
|
||||
attribute to your own trait to include it in the "Important Traits" dialog in documentation.
|
||||
|
||||
The `#[doc(spotlight)]` attribute currently requires the `#![feature(doc_spotlight)]` feature gate.
|
||||
For more information, see [its chapter in the Unstable Book][unstable-spotlight] and [its tracking
|
||||
issue][issue-spotlight].
|
||||
|
||||
[unstable-spotlight]: ../unstable-book/language-features/doc-spotlight.html
|
||||
[issue-spotlight]: https://github.com/rust-lang/rust/issues/45040
|
||||
|
||||
### Exclude certain dependencies from documentation
|
||||
|
||||
The standard library uses several dependencies which, in turn, use several types and traits from the
|
||||
|
30
src/doc/unstable-book/src/language-features/doc-spotlight.md
Normal file
30
src/doc/unstable-book/src/language-features/doc-spotlight.md
Normal file
@ -0,0 +1,30 @@
|
||||
# `doc_spotlight`
|
||||
|
||||
The tracking issue for this feature is: [#45040]
|
||||
|
||||
The `doc_spotlight` feature allows the use of the `spotlight` parameter to the `#[doc]` attribute,
|
||||
to "spotlight" a specific trait on the return values of functions. Adding a `#[doc(spotlight)]`
|
||||
attribute to a trait definition will make rustdoc print extra information for functions which return
|
||||
a type that implements that trait. This attribute is applied to the `Iterator`, `io::Read`, and
|
||||
`io::Write` traits in the standard library.
|
||||
|
||||
You can do this on your own traits, like this:
|
||||
|
||||
```
|
||||
#![feature(doc_spotlight)]
|
||||
|
||||
#[doc(spotlight)]
|
||||
pub trait MyTrait {}
|
||||
|
||||
pub struct MyStruct;
|
||||
impl MyTrait for MyStruct {}
|
||||
|
||||
/// The docs for this function will have an extra line about `MyStruct` implementing `MyTrait`,
|
||||
/// without having to write that yourself!
|
||||
pub fn my_fn() -> MyStruct { MyStruct }
|
||||
```
|
||||
|
||||
This feature was originally implemented in PR [#45039].
|
||||
|
||||
[#45040]: https://github.com/rust-lang/rust/issues/45040
|
||||
[#45039]: https://github.com/rust-lang/rust/pull/45039
|
@ -151,7 +151,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
|
||||
let mut out_tree = BTreeMap { root: Some(node::Root::new_leaf()), length: 0 };
|
||||
|
||||
{
|
||||
let root = out_tree.root.as_mut().unwrap();
|
||||
let root = out_tree.root.as_mut().unwrap(); // unwrap succeeds because we just wrapped
|
||||
let mut out_node = match root.as_mut().force() {
|
||||
Leaf(leaf) => leaf,
|
||||
Internal(_) => unreachable!(),
|
||||
@ -171,14 +171,10 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
|
||||
}
|
||||
Internal(internal) => {
|
||||
let mut out_tree = clone_subtree(internal.first_edge().descend());
|
||||
out_tree.ensure_root_is_owned();
|
||||
|
||||
{
|
||||
// Ideally we'd use the return of ensure_root_is_owned
|
||||
// instead of re-unwrapping here but unfortunately that
|
||||
// borrows all of out_tree and we need access to the
|
||||
// length below.
|
||||
let mut out_node = out_tree.root.as_mut().unwrap().push_level();
|
||||
let out_root = BTreeMap::ensure_is_owned(&mut out_tree.root);
|
||||
let mut out_node = out_root.push_level();
|
||||
let mut in_edge = internal.first_edge();
|
||||
while let Ok(kv) = in_edge.right_kv() {
|
||||
let (k, v) = kv.into_kv();
|
||||
@ -212,7 +208,7 @@ impl<K: Clone, V: Clone> Clone for BTreeMap<K, V> {
|
||||
// Ord` constraint, which this method lacks.
|
||||
BTreeMap { root: None, length: 0 }
|
||||
} else {
|
||||
clone_subtree(self.root.as_ref().unwrap().as_ref())
|
||||
clone_subtree(self.root.as_ref().unwrap().as_ref()) // unwrap succeeds because not empty
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,8 +239,8 @@ where
|
||||
}
|
||||
|
||||
fn replace(&mut self, key: K) -> Option<K> {
|
||||
self.ensure_root_is_owned();
|
||||
match search::search_tree::<marker::Mut<'_>, K, (), K>(self.root.as_mut()?.as_mut(), &key) {
|
||||
let root = Self::ensure_is_owned(&mut self.root);
|
||||
match search::search_tree::<marker::Mut<'_>, K, (), K>(root.as_mut(), &key) {
|
||||
Found(handle) => Some(mem::replace(handle.into_kv_mut().0, key)),
|
||||
GoDown(handle) => {
|
||||
VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }
|
||||
@ -943,7 +939,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
|
||||
// Second, we build a tree from the sorted sequence in linear time.
|
||||
self.from_sorted_iter(iter);
|
||||
self.fix_right_edge();
|
||||
}
|
||||
|
||||
/// Constructs a double-ended iterator over a sub-range of elements in the map.
|
||||
@ -1058,8 +1053,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn entry(&mut self, key: K) -> Entry<'_, K, V> {
|
||||
// FIXME(@porglezomp) Avoid allocating if we don't insert
|
||||
self.ensure_root_is_owned();
|
||||
match search::search_tree(self.root.as_mut().unwrap().as_mut(), &key) {
|
||||
let root = Self::ensure_is_owned(&mut self.root);
|
||||
match search::search_tree(root.as_mut(), &key) {
|
||||
Found(handle) => {
|
||||
Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData })
|
||||
}
|
||||
@ -1070,8 +1065,8 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
}
|
||||
|
||||
fn from_sorted_iter<I: Iterator<Item = (K, V)>>(&mut self, iter: I) {
|
||||
self.ensure_root_is_owned();
|
||||
let mut cur_node = self.root.as_mut().unwrap().as_mut().last_leaf_edge().into_node();
|
||||
let root = Self::ensure_is_owned(&mut self.root);
|
||||
let mut cur_node = root.as_mut().last_leaf_edge().into_node();
|
||||
// Iterate through all key-value pairs, pushing them into nodes at the right level.
|
||||
for (key, value) in iter {
|
||||
// Try to push key-value pair into the current leaf node.
|
||||
@ -1116,11 +1111,12 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
|
||||
self.length += 1;
|
||||
}
|
||||
Self::fix_right_edge(root)
|
||||
}
|
||||
|
||||
fn fix_right_edge(&mut self) {
|
||||
fn fix_right_edge(root: &mut node::Root<K, V>) {
|
||||
// Handle underfull nodes, start from the top.
|
||||
let mut cur_node = self.root.as_mut().unwrap().as_mut();
|
||||
let mut cur_node = root.as_mut();
|
||||
while let Internal(internal) = cur_node.force() {
|
||||
// Check if right-most child is underfull.
|
||||
let mut last_edge = internal.last_edge();
|
||||
@ -1179,16 +1175,17 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
}
|
||||
|
||||
let total_num = self.len();
|
||||
let left_root = self.root.as_mut().unwrap(); // unwrap succeeds because not empty
|
||||
|
||||
let mut right = Self::new();
|
||||
let right_root = right.ensure_root_is_owned();
|
||||
for _ in 0..(self.root.as_ref().unwrap().as_ref().height()) {
|
||||
let right_root = Self::ensure_is_owned(&mut right.root);
|
||||
for _ in 0..left_root.height() {
|
||||
right_root.push_level();
|
||||
}
|
||||
|
||||
{
|
||||
let mut left_node = self.root.as_mut().unwrap().as_mut();
|
||||
let mut right_node = right.root.as_mut().unwrap().as_mut();
|
||||
let mut left_node = left_root.as_mut();
|
||||
let mut right_node = right_root.as_mut();
|
||||
|
||||
loop {
|
||||
let mut split_edge = match search::search_node(left_node, key) {
|
||||
@ -1214,12 +1211,10 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
}
|
||||
}
|
||||
|
||||
self.fix_right_border();
|
||||
right.fix_left_border();
|
||||
left_root.fix_right_border();
|
||||
right_root.fix_left_border();
|
||||
|
||||
if self.root.as_ref().unwrap().as_ref().height()
|
||||
< right.root.as_ref().unwrap().as_ref().height()
|
||||
{
|
||||
if left_root.height() < right_root.height() {
|
||||
self.recalc_length();
|
||||
right.length = total_num - self.len();
|
||||
} else {
|
||||
@ -1301,69 +1296,6 @@ impl<K: Ord, V> BTreeMap<K, V> {
|
||||
|
||||
self.length = dfs(self.root.as_ref().unwrap().as_ref());
|
||||
}
|
||||
|
||||
/// Removes empty levels on the top.
|
||||
fn fix_top(&mut self) {
|
||||
loop {
|
||||
{
|
||||
let node = self.root.as_ref().unwrap().as_ref();
|
||||
if node.height() == 0 || node.len() > 0 {
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.root.as_mut().unwrap().pop_level();
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_right_border(&mut self) {
|
||||
self.fix_top();
|
||||
|
||||
{
|
||||
let mut cur_node = self.root.as_mut().unwrap().as_mut();
|
||||
|
||||
while let Internal(node) = cur_node.force() {
|
||||
let mut last_kv = node.last_kv();
|
||||
|
||||
if last_kv.can_merge() {
|
||||
cur_node = last_kv.merge().descend();
|
||||
} else {
|
||||
let right_len = last_kv.reborrow().right_edge().descend().len();
|
||||
// `MINLEN + 1` to avoid readjust if merge happens on the next level.
|
||||
if right_len < node::MIN_LEN + 1 {
|
||||
last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
|
||||
}
|
||||
cur_node = last_kv.right_edge().descend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.fix_top();
|
||||
}
|
||||
|
||||
/// The symmetric clone of `fix_right_border`.
|
||||
fn fix_left_border(&mut self) {
|
||||
self.fix_top();
|
||||
|
||||
{
|
||||
let mut cur_node = self.root.as_mut().unwrap().as_mut();
|
||||
|
||||
while let Internal(node) = cur_node.force() {
|
||||
let mut first_kv = node.first_kv();
|
||||
|
||||
if first_kv.can_merge() {
|
||||
cur_node = first_kv.merge().descend();
|
||||
} else {
|
||||
let left_len = first_kv.reborrow().left_edge().descend().len();
|
||||
if left_len < node::MIN_LEN + 1 {
|
||||
first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
|
||||
}
|
||||
cur_node = first_kv.left_edge().descend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.fix_top();
|
||||
}
|
||||
}
|
||||
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
@ -2321,9 +2253,9 @@ impl<K, V> BTreeMap<K, V> {
|
||||
}
|
||||
|
||||
/// If the root node is the empty (non-allocated) root node, allocate our
|
||||
/// own node.
|
||||
fn ensure_root_is_owned(&mut self) -> &mut node::Root<K, V> {
|
||||
self.root.get_or_insert_with(node::Root::new_leaf)
|
||||
/// own node. Is an associated function to avoid borrowing the entire BTreeMap.
|
||||
fn ensure_is_owned(root: &mut Option<node::Root<K, V>>) -> &mut node::Root<K, V> {
|
||||
root.get_or_insert_with(node::Root::new_leaf)
|
||||
}
|
||||
}
|
||||
|
||||
@ -2825,6 +2757,65 @@ impl<'a, K: 'a, V: 'a> Handle<NodeRef<marker::Mut<'a>, K, V, marker::LeafOrInter
|
||||
}
|
||||
}
|
||||
|
||||
impl<K, V> node::Root<K, V> {
|
||||
/// Removes empty levels on the top, but keep an empty leaf if the entire tree is empty.
|
||||
fn fix_top(&mut self) {
|
||||
while self.height() > 0 && self.as_ref().len() == 0 {
|
||||
self.pop_level();
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_right_border(&mut self) {
|
||||
self.fix_top();
|
||||
|
||||
{
|
||||
let mut cur_node = self.as_mut();
|
||||
|
||||
while let Internal(node) = cur_node.force() {
|
||||
let mut last_kv = node.last_kv();
|
||||
|
||||
if last_kv.can_merge() {
|
||||
cur_node = last_kv.merge().descend();
|
||||
} else {
|
||||
let right_len = last_kv.reborrow().right_edge().descend().len();
|
||||
// `MINLEN + 1` to avoid readjust if merge happens on the next level.
|
||||
if right_len < node::MIN_LEN + 1 {
|
||||
last_kv.bulk_steal_left(node::MIN_LEN + 1 - right_len);
|
||||
}
|
||||
cur_node = last_kv.right_edge().descend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.fix_top();
|
||||
}
|
||||
|
||||
/// The symmetric clone of `fix_right_border`.
|
||||
fn fix_left_border(&mut self) {
|
||||
self.fix_top();
|
||||
|
||||
{
|
||||
let mut cur_node = self.as_mut();
|
||||
|
||||
while let Internal(node) = cur_node.force() {
|
||||
let mut first_kv = node.first_kv();
|
||||
|
||||
if first_kv.can_merge() {
|
||||
cur_node = first_kv.merge().descend();
|
||||
} else {
|
||||
let left_len = first_kv.reborrow().left_edge().descend().len();
|
||||
if left_len < node::MIN_LEN + 1 {
|
||||
first_kv.bulk_steal_right(node::MIN_LEN + 1 - left_len);
|
||||
}
|
||||
cur_node = first_kv.left_edge().descend();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.fix_top();
|
||||
}
|
||||
}
|
||||
|
||||
enum UnderflowResult<'a, K, V> {
|
||||
AtRoot,
|
||||
Merged(Handle<NodeRef<marker::Mut<'a>, K, V, marker::Internal>, marker::Edge>, bool, usize),
|
||||
|
@ -153,6 +153,11 @@ unsafe impl<K: Sync, V: Sync> Sync for Root<K, V> {}
|
||||
unsafe impl<K: Send, V: Send> Send for Root<K, V> {}
|
||||
|
||||
impl<K, V> Root<K, V> {
|
||||
/// Returns the number of levels below the root.
|
||||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
/// Returns a new owned tree, with its own root node that is initially empty.
|
||||
pub fn new_leaf() -> Self {
|
||||
Root { node: BoxedNode::from_leaf(Box::new(unsafe { LeafNode::new() })), height: 0 }
|
||||
|
@ -24,6 +24,7 @@ use crate::task::{Context, Poll};
|
||||
/// `.await` the value.
|
||||
///
|
||||
/// [`Waker`]: ../task/struct.Waker.html
|
||||
#[doc(spotlight)]
|
||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
#[lang = "future_trait"]
|
||||
|
@ -1126,7 +1126,7 @@ extern "rust-intrinsic" {
|
||||
///
|
||||
/// // use `u32::from_ne_bytes` instead
|
||||
/// let num = u32::from_ne_bytes(raw_bytes);
|
||||
/// // or use `u32::from_le_bytes` or `u32::from_ge_bytes` to specify the endianness
|
||||
/// // or use `u32::from_le_bytes` or `u32::from_be_bytes` to specify the endianness
|
||||
/// let num = u32::from_le_bytes(raw_bytes);
|
||||
/// assert_eq!(num, 0x12345678);
|
||||
/// let num = u32::from_be_bytes(raw_bytes);
|
||||
|
@ -92,6 +92,7 @@ fn _assert_is_object_safe(_: &dyn Iterator<Item = ()>) {}
|
||||
label = "`{Self}` is not an iterator",
|
||||
message = "`{Self}` is not an iterator"
|
||||
)]
|
||||
#[doc(spotlight)]
|
||||
#[must_use = "iterators are lazy and do nothing unless consumed"]
|
||||
pub trait Iterator {
|
||||
/// The type of the elements being iterated over.
|
||||
|
@ -96,6 +96,7 @@
|
||||
#![feature(custom_inner_attributes)]
|
||||
#![feature(decl_macro)]
|
||||
#![feature(doc_cfg)]
|
||||
#![cfg_attr(not(bootstrap), feature(doc_spotlight))]
|
||||
#![feature(duration_consts_2)]
|
||||
#![feature(extern_types)]
|
||||
#![feature(fundamental)]
|
||||
|
@ -253,6 +253,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
|
||||
include => external_doc
|
||||
cfg => doc_cfg
|
||||
masked => doc_masked
|
||||
spotlight => doc_spotlight
|
||||
alias => doc_alias
|
||||
keyword => doc_keyword
|
||||
);
|
||||
|
@ -452,6 +452,7 @@ E0766: include_str!("./error_codes/E0766.md"),
|
||||
E0767: include_str!("./error_codes/E0767.md"),
|
||||
E0768: include_str!("./error_codes/E0768.md"),
|
||||
E0769: include_str!("./error_codes/E0769.md"),
|
||||
E0770: include_str!("./error_codes/E0770.md"),
|
||||
;
|
||||
// E0006, // merged with E0005
|
||||
// E0008, // cannot bind by-move into a pattern guard
|
||||
|
@ -3,7 +3,7 @@
|
||||
Const parameters cannot depend on type parameters.
|
||||
The following is therefore invalid:
|
||||
|
||||
```compile_fail,E0741
|
||||
```compile_fail,E0770
|
||||
#![feature(const_generics)]
|
||||
|
||||
fn const_id<T, const N: T>() -> T { // error
|
||||
|
@ -1,5 +1,5 @@
|
||||
A `#![feature]` attribute was declared for a feature that is stable in
|
||||
the current edition, but not in all editions.
|
||||
A `#![feature]` attribute was declared for a feature that is stable in the
|
||||
current edition, but not in all editions.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
An unknown tool name found in scoped lint
|
||||
An unknown tool name was found in a scoped lint.
|
||||
|
||||
Erroneous code examples:
|
||||
|
||||
|
15
src/librustc_error_codes/error_codes/E0770.md
Normal file
15
src/librustc_error_codes/error_codes/E0770.md
Normal file
@ -0,0 +1,15 @@
|
||||
The type of a const parameter references other generic parameters.
|
||||
|
||||
Erroneous code example:
|
||||
|
||||
```compile_fail,E0770
|
||||
#![feature(const_generics)]
|
||||
fn foo<T, const N: T>() {} // error!
|
||||
```
|
||||
|
||||
To fix this error, use a concrete type for the const parameter:
|
||||
|
||||
```
|
||||
#![feature(const_generics)]
|
||||
fn foo<T, const N: usize>() {}
|
||||
```
|
@ -368,6 +368,9 @@ declare_features! (
|
||||
/// Allows `#[doc(masked)]`.
|
||||
(active, doc_masked, "1.21.0", Some(44027), None),
|
||||
|
||||
/// Allows `#[doc(spotlight)]`.
|
||||
(active, doc_spotlight, "1.22.0", Some(45040), None),
|
||||
|
||||
/// Allows `#[doc(include = "some-file")]`.
|
||||
(active, external_doc, "1.22.0", Some(44732), None),
|
||||
|
||||
|
@ -2687,7 +2687,7 @@ pub enum Node<'hir> {
|
||||
Crate(&'hir CrateItem<'hir>),
|
||||
}
|
||||
|
||||
impl Node<'_> {
|
||||
impl<'hir> Node<'hir> {
|
||||
pub fn ident(&self) -> Option<Ident> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { ident, .. })
|
||||
@ -2698,7 +2698,7 @@ impl Node<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fn_decl(&self) -> Option<&FnDecl<'_>> {
|
||||
pub fn fn_decl(&self) -> Option<&FnDecl<'hir>> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { kind: TraitItemKind::Fn(fn_sig, _), .. })
|
||||
| Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(fn_sig, _), .. })
|
||||
@ -2722,7 +2722,7 @@ impl Node<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generics(&self) -> Option<&Generics<'_>> {
|
||||
pub fn generics(&self) -> Option<&'hir Generics<'hir>> {
|
||||
match self {
|
||||
Node::TraitItem(TraitItem { generics, .. })
|
||||
| Node::ImplItem(ImplItem { generics, .. }) => Some(generics),
|
||||
|
@ -354,13 +354,7 @@ fn configure_and_expand_inner<'a>(
|
||||
)
|
||||
});
|
||||
|
||||
// If we're actually rustdoc then there's no need to actually compile
|
||||
// anything, so switch everything to just looping
|
||||
let mut should_loop = sess.opts.actually_rustdoc;
|
||||
if let Some(PpMode::PpmSource(PpSourceMode::PpmEveryBodyLoops)) = sess.opts.pretty {
|
||||
should_loop |= true;
|
||||
}
|
||||
if should_loop {
|
||||
log::debug!("replacing bodies with loop {{}}");
|
||||
util::ReplaceBodyWithLoop::new(&mut resolver).visit_crate(&mut krate);
|
||||
}
|
||||
|
@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
|
||||
lint: &'static lint::Lint,
|
||||
source_info: SourceInfo,
|
||||
message: &'static str,
|
||||
panic: AssertKind<ConstInt>,
|
||||
panic: AssertKind<impl std::fmt::Debug>,
|
||||
) -> Option<()> {
|
||||
let lint_root = self.lint_root(source_info)?;
|
||||
self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, |lint| {
|
||||
@ -1004,11 +1004,27 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> {
|
||||
let expected = ScalarMaybeUninit::from(Scalar::from_bool(*expected));
|
||||
let value_const = self.ecx.read_scalar(value).unwrap();
|
||||
if expected != value_const {
|
||||
enum DbgVal<T> {
|
||||
Val(T),
|
||||
Underscore,
|
||||
}
|
||||
impl<T: std::fmt::Debug> std::fmt::Debug for DbgVal<T> {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Val(val) => val.fmt(fmt),
|
||||
Self::Underscore => fmt.write_str("_"),
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut eval_to_int = |op| {
|
||||
let op = self
|
||||
.eval_operand(op, source_info)
|
||||
.expect("if we got here, it must be const");
|
||||
self.ecx.read_immediate(op).unwrap().to_const_int()
|
||||
// This can be `None` if the lhs wasn't const propagated and we just
|
||||
// triggered the assert on the value of the rhs.
|
||||
match self.eval_operand(op, source_info) {
|
||||
Some(op) => {
|
||||
DbgVal::Val(self.ecx.read_immediate(op).unwrap().to_const_int())
|
||||
}
|
||||
None => DbgVal::Underscore,
|
||||
}
|
||||
};
|
||||
let msg = match msg {
|
||||
AssertKind::DivisionByZero(op) => {
|
||||
|
@ -70,6 +70,8 @@ impl CheckAttrVisitor<'tcx> {
|
||||
self.check_target_feature(attr, span, target)
|
||||
} else if attr.check_name(sym::track_caller) {
|
||||
self.check_track_caller(&attr.span, attrs, span, target)
|
||||
} else if attr.check_name(sym::doc) {
|
||||
self.check_doc_alias(attr)
|
||||
} else {
|
||||
true
|
||||
};
|
||||
@ -216,6 +218,34 @@ impl CheckAttrVisitor<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_doc_alias(&self, attr: &Attribute) -> bool {
|
||||
if let Some(mi) = attr.meta() {
|
||||
if let Some(list) = mi.meta_item_list() {
|
||||
for meta in list {
|
||||
if meta.check_name(sym::alias) {
|
||||
if !meta.is_value_str()
|
||||
|| meta
|
||||
.value_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(String::new)
|
||||
.is_empty()
|
||||
{
|
||||
self.tcx
|
||||
.sess
|
||||
.struct_span_err(
|
||||
meta.span(),
|
||||
"doc alias attribute expects a string: #[doc(alias = \"0\")]",
|
||||
)
|
||||
.emit();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
/// Checks if the `#[repr]` attributes on `item` are valid.
|
||||
fn check_repr(
|
||||
&self,
|
||||
|
@ -442,6 +442,19 @@ impl<'a> Resolver<'a> {
|
||||
);
|
||||
err
|
||||
}
|
||||
ResolutionError::ParamInTyOfConstArg(name) => {
|
||||
let mut err = struct_span_err!(
|
||||
self.session,
|
||||
span,
|
||||
E0770,
|
||||
"the type of const parameters must not depend on other generic parameters"
|
||||
);
|
||||
err.span_label(
|
||||
span,
|
||||
format!("the type must not depend on the parameter `{}`", name),
|
||||
);
|
||||
err
|
||||
}
|
||||
ResolutionError::SelfInTyParamDefault => {
|
||||
let mut err = struct_span_err!(
|
||||
self.session,
|
||||
|
@ -123,6 +123,10 @@ crate enum RibKind<'a> {
|
||||
/// from the default of a type parameter because they're not declared
|
||||
/// before said type parameter. Also see the `visit_generics` override.
|
||||
ForwardTyParamBanRibKind,
|
||||
|
||||
/// We are inside of the type of a const parameter. Can't refer to any
|
||||
/// parameters.
|
||||
ConstParamTyRibKind,
|
||||
}
|
||||
|
||||
impl RibKind<'_> {
|
||||
@ -135,7 +139,8 @@ impl RibKind<'_> {
|
||||
| FnItemRibKind
|
||||
| ConstantItemRibKind
|
||||
| ModuleRibKind(_)
|
||||
| MacroDefinition(_) => false,
|
||||
| MacroDefinition(_)
|
||||
| ConstParamTyRibKind => false,
|
||||
AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true,
|
||||
}
|
||||
}
|
||||
@ -394,13 +399,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
/// Fields used to add information to diagnostic errors.
|
||||
diagnostic_metadata: DiagnosticMetadata<'ast>,
|
||||
|
||||
/// State used to know whether to ignore resolution errors for function bodies.
|
||||
///
|
||||
/// In particular, rustdoc uses this to avoid giving errors for `cfg()` items.
|
||||
/// In most cases this will be `None`, in which case errors will always be reported.
|
||||
/// If it is `Some(_)`, then it will be updated when entering a nested function or trait body.
|
||||
in_func_body: bool,
|
||||
}
|
||||
|
||||
/// Walks the whole crate in DFS order, visiting each item, resolving names as it goes.
|
||||
impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
fn visit_item(&mut self, item: &'ast Item) {
|
||||
let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item));
|
||||
// Always report errors in items we just entered.
|
||||
let old_ignore = replace(&mut self.in_func_body, false);
|
||||
self.resolve_item(item);
|
||||
self.in_func_body = old_ignore;
|
||||
self.diagnostic_metadata.current_item = prev;
|
||||
}
|
||||
fn visit_arm(&mut self, arm: &'ast Arm) {
|
||||
@ -497,6 +512,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
|
||||
visit::walk_fn_ret_ty(this, &declaration.output);
|
||||
|
||||
// Ignore errors in function bodies if this is rustdoc
|
||||
// Be sure not to set this until the function signature has been resolved.
|
||||
let previous_state = replace(&mut this.in_func_body, true);
|
||||
// Resolve the function body, potentially inside the body of an async closure
|
||||
match fn_kind {
|
||||
FnKind::Fn(.., body) => walk_list!(this, visit_block, body),
|
||||
@ -504,6 +522,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
};
|
||||
|
||||
debug!("(resolving function) leaving function");
|
||||
this.in_func_body = previous_state;
|
||||
})
|
||||
});
|
||||
self.diagnostic_metadata.current_function = previous_value;
|
||||
@ -562,7 +581,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> {
|
||||
for bound in ¶m.bounds {
|
||||
self.visit_param_bound(bound);
|
||||
}
|
||||
self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
|
||||
self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
|
||||
self.visit_ty(ty);
|
||||
self.ribs[TypeNS].pop().unwrap();
|
||||
self.ribs[ValueNS].pop().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -644,6 +667,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
label_ribs: Vec::new(),
|
||||
current_trait_ref: None,
|
||||
diagnostic_metadata: DiagnosticMetadata::default(),
|
||||
// errors at module scope should always be reported
|
||||
in_func_body: false,
|
||||
}
|
||||
}
|
||||
|
||||
@ -757,7 +782,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
return if self.is_label_valid_from_rib(i) {
|
||||
Some(*id)
|
||||
} else {
|
||||
self.r.report_error(
|
||||
self.report_error(
|
||||
original_span,
|
||||
ResolutionError::UnreachableLabel {
|
||||
name: label.name,
|
||||
@ -775,7 +800,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label));
|
||||
}
|
||||
|
||||
self.r.report_error(
|
||||
self.report_error(
|
||||
original_span,
|
||||
ResolutionError::UndeclaredLabel { name: label.name, suggestion },
|
||||
);
|
||||
@ -798,7 +823,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
| ItemRibKind(..)
|
||||
| ConstantItemRibKind
|
||||
| ModuleRibKind(..)
|
||||
| ForwardTyParamBanRibKind => {
|
||||
| ForwardTyParamBanRibKind
|
||||
| ConstParamTyRibKind => {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -833,7 +859,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
};
|
||||
let report_error = |this: &Self, ns| {
|
||||
let what = if ns == TypeNS { "type parameters" } else { "local variables" };
|
||||
this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what));
|
||||
if this.should_report_errs() {
|
||||
this.r
|
||||
.session
|
||||
.span_err(ident.span, &format!("imports cannot refer to {}", what));
|
||||
}
|
||||
};
|
||||
|
||||
for &ns in nss {
|
||||
@ -1008,7 +1038,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
if seen_bindings.contains_key(&ident) {
|
||||
let span = seen_bindings.get(&ident).unwrap();
|
||||
let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span);
|
||||
self.r.report_error(param.ident.span, err);
|
||||
self.report_error(param.ident.span, err);
|
||||
}
|
||||
seen_bindings.entry(ident).or_insert(param.ident.span);
|
||||
|
||||
@ -1274,7 +1304,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
.is_err()
|
||||
{
|
||||
let path = &self.current_trait_ref.as_ref().unwrap().1.path;
|
||||
self.r.report_error(span, err(ident.name, &path_names_to_string(path)));
|
||||
self.report_error(span, err(ident.name, &path_names_to_string(path)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1289,6 +1319,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
}
|
||||
|
||||
fn resolve_local(&mut self, local: &'ast Local) {
|
||||
debug!("resolving local ({:?})", local);
|
||||
// Resolve the type.
|
||||
walk_list!(self, visit_ty, &local.ty);
|
||||
|
||||
@ -1390,7 +1421,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
if inconsistent_vars.contains_key(name) {
|
||||
v.could_be_path = false;
|
||||
}
|
||||
self.r.report_error(
|
||||
self.report_error(
|
||||
*v.origin.iter().next().unwrap(),
|
||||
ResolutionError::VariableNotBoundInPattern(v),
|
||||
);
|
||||
@ -1400,7 +1431,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
let mut inconsistent_vars = inconsistent_vars.iter().collect::<Vec<_>>();
|
||||
inconsistent_vars.sort();
|
||||
for (name, v) in inconsistent_vars {
|
||||
self.r.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
|
||||
self.report_error(v.0, ResolutionError::VariableBoundWithDifferentMode(*name, v.1));
|
||||
}
|
||||
|
||||
// 5) Finally bubble up all the binding maps.
|
||||
@ -1550,7 +1581,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
// `Variant(a, a)`:
|
||||
_ => IdentifierBoundMoreThanOnceInSamePattern,
|
||||
};
|
||||
self.r.report_error(ident.span, error(ident.name));
|
||||
self.report_error(ident.span, error(ident.name));
|
||||
}
|
||||
|
||||
// Record as bound if it's valid:
|
||||
@ -1624,7 +1655,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
// to something unusable as a pattern (e.g., constructor function),
|
||||
// but we still conservatively report an error, see
|
||||
// issues/33118#issuecomment-233962221 for one reason why.
|
||||
self.r.report_error(
|
||||
self.report_error(
|
||||
ident.span,
|
||||
ResolutionError::BindingShadowsSomethingUnacceptable(
|
||||
pat_src.descr(),
|
||||
@ -1677,18 +1708,27 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
source: PathSource<'ast>,
|
||||
crate_lint: CrateLint,
|
||||
) -> PartialRes {
|
||||
log::debug!("smart_resolve_path_fragment(id={:?},qself={:?},path={:?}", id, qself, path);
|
||||
let ns = source.namespace();
|
||||
let is_expected = &|res| source.is_expected(res);
|
||||
|
||||
let report_errors = |this: &mut Self, res: Option<Res>| {
|
||||
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
|
||||
if this.should_report_errs() {
|
||||
let (err, candidates) = this.smart_resolve_report_errors(path, span, source, res);
|
||||
|
||||
let def_id = this.parent_scope.module.normal_ancestor_id;
|
||||
let instead = res.is_some();
|
||||
let suggestion =
|
||||
if res.is_none() { this.report_missing_type_error(path) } else { None };
|
||||
let def_id = this.parent_scope.module.normal_ancestor_id;
|
||||
let instead = res.is_some();
|
||||
let suggestion =
|
||||
if res.is_none() { this.report_missing_type_error(path) } else { None };
|
||||
|
||||
this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion });
|
||||
this.r.use_injections.push(UseError {
|
||||
err,
|
||||
candidates,
|
||||
def_id,
|
||||
instead,
|
||||
suggestion,
|
||||
});
|
||||
}
|
||||
|
||||
PartialRes::new(Res::Err)
|
||||
};
|
||||
@ -1746,13 +1786,17 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
let def_id = this.parent_scope.module.normal_ancestor_id;
|
||||
|
||||
this.r.use_injections.push(UseError {
|
||||
err,
|
||||
candidates,
|
||||
def_id,
|
||||
instead: false,
|
||||
suggestion: None,
|
||||
});
|
||||
if this.should_report_errs() {
|
||||
this.r.use_injections.push(UseError {
|
||||
err,
|
||||
candidates,
|
||||
def_id,
|
||||
instead: false,
|
||||
suggestion: None,
|
||||
});
|
||||
} else {
|
||||
err.cancel();
|
||||
}
|
||||
|
||||
// We don't return `Some(parent_err)` here, because the error will
|
||||
// be already printed as part of the `use` injections
|
||||
@ -1809,7 +1853,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
|
||||
Err(err) => {
|
||||
if let Some(err) = report_errors_for_call(self, err) {
|
||||
self.r.report_error(err.span, err.node);
|
||||
self.report_error(err.span, err.node);
|
||||
}
|
||||
|
||||
PartialRes::new(Res::Err)
|
||||
@ -1843,6 +1887,21 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
|
||||
if let Some(LexicalScopeBinding::Res(res)) = binding { res != Res::Err } else { false }
|
||||
}
|
||||
|
||||
/// A wrapper around [`Resolver::report_error`].
|
||||
///
|
||||
/// This doesn't emit errors for function bodies if this is rustdoc.
|
||||
fn report_error(&self, span: Span, resolution_error: ResolutionError<'_>) {
|
||||
if self.should_report_errs() {
|
||||
self.r.report_error(span, resolution_error);
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
/// If we're actually rustdoc then avoid giving a name resolution error for `cfg()` items.
|
||||
fn should_report_errs(&self) -> bool {
|
||||
!(self.r.session.opts.actually_rustdoc && self.in_func_body)
|
||||
}
|
||||
|
||||
// Resolve in alternative namespaces if resolution in the primary namespace fails.
|
||||
fn resolve_qpath_anywhere(
|
||||
&mut self,
|
||||
|
@ -214,6 +214,8 @@ enum ResolutionError<'a> {
|
||||
BindingShadowsSomethingUnacceptable(&'static str, Symbol, &'a NameBinding<'a>),
|
||||
/// Error E0128: type parameters with a default cannot use forward-declared identifiers.
|
||||
ForwardDeclaredTyParam, // FIXME(const_generics:defaults)
|
||||
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
|
||||
ParamInTyOfConstArg(Symbol),
|
||||
/// Error E0735: type parameters with a default cannot use `Self`
|
||||
SelfInTyParamDefault,
|
||||
/// Error E0767: use of unreachable label
|
||||
@ -2480,6 +2482,12 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
ConstParamTyRibKind => {
|
||||
if record_used {
|
||||
self.report_error(span, ParamInTyOfConstArg(rib_ident.name));
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(res_err) = res_err {
|
||||
@ -2503,6 +2511,15 @@ impl<'a> Resolver<'a> {
|
||||
// This was an attempt to use a type parameter outside its scope.
|
||||
ItemRibKind(has_generic_params) => has_generic_params,
|
||||
FnItemRibKind => HasGenericParams::Yes,
|
||||
ConstParamTyRibKind => {
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
};
|
||||
|
||||
if record_used {
|
||||
@ -2527,9 +2544,24 @@ impl<'a> Resolver<'a> {
|
||||
}
|
||||
for rib in ribs {
|
||||
let has_generic_params = match rib.kind {
|
||||
NormalRibKind
|
||||
| ClosureOrAsyncRibKind
|
||||
| AssocItemRibKind
|
||||
| ModuleRibKind(..)
|
||||
| MacroDefinition(..)
|
||||
| ForwardTyParamBanRibKind
|
||||
| ConstantItemRibKind => continue,
|
||||
ItemRibKind(has_generic_params) => has_generic_params,
|
||||
FnItemRibKind => HasGenericParams::Yes,
|
||||
_ => continue,
|
||||
ConstParamTyRibKind => {
|
||||
if record_used {
|
||||
self.report_error(
|
||||
span,
|
||||
ResolutionError::ParamInTyOfConstArg(rib_ident.name),
|
||||
);
|
||||
}
|
||||
return Res::Err;
|
||||
}
|
||||
};
|
||||
|
||||
// This was an attempt to use a const parameter outside its scope.
|
||||
|
@ -400,6 +400,7 @@ symbols! {
|
||||
doc_cfg,
|
||||
doc_keyword,
|
||||
doc_masked,
|
||||
doc_spotlight,
|
||||
doctest,
|
||||
document_private_items,
|
||||
dotdot_in_tuple_patterns,
|
||||
@ -968,6 +969,7 @@ symbols! {
|
||||
soft,
|
||||
specialization,
|
||||
speed,
|
||||
spotlight,
|
||||
sqrtf32,
|
||||
sqrtf64,
|
||||
sse4a_target_feature,
|
||||
|
@ -937,6 +937,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
// legal to implement.
|
||||
let mut candidates = all_traits(self.tcx)
|
||||
.into_iter()
|
||||
// Don't issue suggestions for unstable traits since they're
|
||||
// unlikely to be implementable anyway
|
||||
.filter(|info| match self.tcx.lookup_stability(info.def_id) {
|
||||
Some(attr) => attr.level.is_stable(),
|
||||
None => true,
|
||||
})
|
||||
.filter(|info| {
|
||||
// We approximate the coherence rules to only suggest
|
||||
// traits that are legal to implement by requiring that
|
||||
|
@ -29,7 +29,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
|
||||
use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
|
||||
use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor};
|
||||
use rustc_hir::weak_lang_items;
|
||||
use rustc_hir::{GenericParamKind, Node};
|
||||
use rustc_hir::{GenericParamKind, HirId, Node};
|
||||
use rustc_middle::hir::map::blocks::FnLikeNode;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
|
||||
@ -1155,6 +1155,35 @@ fn has_late_bound_regions<'tcx>(tcx: TyCtxt<'tcx>, node: Node<'tcx>) -> Option<S
|
||||
}
|
||||
}
|
||||
|
||||
struct AnonConstInParamListDetector {
|
||||
in_param_list: bool,
|
||||
found_anon_const_in_list: bool,
|
||||
ct: HirId,
|
||||
}
|
||||
|
||||
impl<'v> Visitor<'v> for AnonConstInParamListDetector {
|
||||
type Map = intravisit::ErasedMap<'v>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
NestedVisitorMap::None
|
||||
}
|
||||
|
||||
fn visit_generic_param(&mut self, p: &'v hir::GenericParam<'v>) {
|
||||
let prev = self.in_param_list;
|
||||
self.in_param_list = true;
|
||||
intravisit::walk_generic_param(self, p);
|
||||
self.in_param_list = prev;
|
||||
}
|
||||
|
||||
fn visit_anon_const(&mut self, c: &'v hir::AnonConst) {
|
||||
if self.in_param_list && self.ct == c.hir_id {
|
||||
self.found_anon_const_in_list = true;
|
||||
} else {
|
||||
intravisit::walk_anon_const(self, c)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
use rustc_hir::*;
|
||||
|
||||
@ -1176,10 +1205,32 @@ fn generics_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::Generics {
|
||||
let parent_id = tcx.hir().get_parent_item(hir_id);
|
||||
let parent_def_id = tcx.hir().local_def_id(parent_id);
|
||||
|
||||
// HACK(eddyb) this provides the correct generics when
|
||||
// `feature(const_generics)` is enabled, so that const expressions
|
||||
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||
if tcx.lazy_normalization() {
|
||||
let mut in_param_list = false;
|
||||
for (_parent, node) in tcx.hir().parent_iter(hir_id) {
|
||||
if let Some(generics) = node.generics() {
|
||||
let mut visitor = AnonConstInParamListDetector {
|
||||
in_param_list: false,
|
||||
found_anon_const_in_list: false,
|
||||
ct: hir_id,
|
||||
};
|
||||
|
||||
visitor.visit_generics(generics);
|
||||
in_param_list = visitor.found_anon_const_in_list;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if in_param_list {
|
||||
// We do not allow generic parameters in anon consts if we are inside
|
||||
// of a param list.
|
||||
//
|
||||
// This affects both default type bindings, e.g. `struct<T, U = [u8; std::mem::size_of::<T>()]>(T, U)`,
|
||||
// and the types of const parameters, e.g. `struct V<const N: usize, const M: [u8; N]>();`.
|
||||
None
|
||||
} else if tcx.lazy_normalization() {
|
||||
// HACK(eddyb) this provides the correct generics when
|
||||
// `feature(const_generics)` is enabled, so that const expressions
|
||||
// used with const generics, e.g. `Foo<{N+1}>`, can work at all.
|
||||
Some(parent_def_id.to_def_id())
|
||||
} else {
|
||||
let parent_node = tcx.hir().get(tcx.hir().get_parent_node(hir_id));
|
||||
|
@ -11,8 +11,10 @@ use rustc_hir as hir;
|
||||
use rustc_hir::def::Res;
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_middle::ty::{self, adjustment, TyCtxt};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
|
||||
use crate::mem_categorization as mc;
|
||||
use rustc_span::Span;
|
||||
@ -396,6 +398,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
&*with_expr,
|
||||
with_place.clone(),
|
||||
with_field.ty(self.tcx(), substs),
|
||||
mc::ProjectionKind::Field(f_index as u32, VariantIdx::new(0)),
|
||||
);
|
||||
self.delegate_consume(&field_place);
|
||||
}
|
||||
|
@ -54,11 +54,14 @@ use rustc_middle::ty::{self, Ty, TyCtxt};
|
||||
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::{DefKind, Res};
|
||||
use rustc_hir::def::{CtorOf, DefKind, Res};
|
||||
use rustc_hir::def_id::LocalDefId;
|
||||
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
|
||||
use rustc_hir::PatKind;
|
||||
use rustc_index::vec::Idx;
|
||||
use rustc_infer::infer::InferCtxt;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use rustc_trait_selection::infer::InferCtxtExt;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -77,8 +80,20 @@ pub enum PlaceBase {
|
||||
pub enum ProjectionKind {
|
||||
/// A dereference of a pointer, reference or `Box<T>` of the given type
|
||||
Deref,
|
||||
/// An index or a field
|
||||
Other,
|
||||
|
||||
/// `B.F` where `B` is the base expression and `F` is
|
||||
/// the field. The field is identified by which variant
|
||||
/// it appears in along with a field index. The variant
|
||||
/// is used for enums.
|
||||
Field(u32, VariantIdx),
|
||||
|
||||
/// Some index like `B[x]`, where `B` is the base
|
||||
/// expression. We don't preserve the index `x` because
|
||||
/// we won't need it.
|
||||
Index,
|
||||
|
||||
/// A subslice covering a range of values like `B[x..y]`.
|
||||
Subslice,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@ -406,7 +421,20 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
hir::ExprKind::Field(ref base, _) => {
|
||||
let base = self.cat_expr(&base)?;
|
||||
debug!("cat_expr(cat_field): id={} expr={:?} base={:?}", expr.hir_id, expr, base);
|
||||
Ok(self.cat_projection(expr, base, expr_ty))
|
||||
|
||||
let field_idx = self
|
||||
.tables
|
||||
.field_indices()
|
||||
.get(expr.hir_id)
|
||||
.cloned()
|
||||
.expect("Field index not found");
|
||||
|
||||
Ok(self.cat_projection(
|
||||
expr,
|
||||
base,
|
||||
expr_ty,
|
||||
ProjectionKind::Field(field_idx as u32, VariantIdx::new(0)),
|
||||
))
|
||||
}
|
||||
|
||||
hir::ExprKind::Index(ref base, _) => {
|
||||
@ -419,7 +447,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
self.cat_overloaded_place(expr, base)
|
||||
} else {
|
||||
let base = self.cat_expr(&base)?;
|
||||
Ok(self.cat_projection(expr, base, expr_ty))
|
||||
Ok(self.cat_projection(expr, base, expr_ty, ProjectionKind::Index))
|
||||
}
|
||||
}
|
||||
|
||||
@ -533,9 +561,10 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
node: &N,
|
||||
base_place: PlaceWithHirId<'tcx>,
|
||||
ty: Ty<'tcx>,
|
||||
kind: ProjectionKind,
|
||||
) -> PlaceWithHirId<'tcx> {
|
||||
let mut projections = base_place.place.projections;
|
||||
projections.push(Projection { kind: ProjectionKind::Other, ty: ty });
|
||||
projections.push(Projection { kind: kind, ty: ty });
|
||||
let ret = PlaceWithHirId::new(
|
||||
node.hir_id(),
|
||||
base_place.place.base_ty,
|
||||
@ -609,6 +638,75 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
self.cat_pattern_(place, pat, &mut op)
|
||||
}
|
||||
|
||||
/// Returns the variant index for an ADT used within a Struct or TupleStruct pattern
|
||||
/// Here `pat_hir_id` is the HirId of the pattern itself.
|
||||
fn variant_index_for_adt(
|
||||
&self,
|
||||
qpath: &hir::QPath<'_>,
|
||||
pat_hir_id: hir::HirId,
|
||||
span: Span,
|
||||
) -> McResult<VariantIdx> {
|
||||
let res = self.tables.qpath_res(qpath, pat_hir_id);
|
||||
let ty = self.tables.node_type(pat_hir_id);
|
||||
let adt_def = match ty.kind {
|
||||
ty::Adt(adt_def, _) => adt_def,
|
||||
_ => {
|
||||
self.tcx()
|
||||
.sess
|
||||
.delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
|
||||
match res {
|
||||
Res::Def(DefKind::Variant, variant_id) => Ok(adt_def.variant_index_with_id(variant_id)),
|
||||
Res::Def(DefKind::Ctor(CtorOf::Variant, ..), variant_ctor_id) => {
|
||||
Ok(adt_def.variant_index_with_ctor_id(variant_ctor_id))
|
||||
}
|
||||
Res::Def(DefKind::Ctor(CtorOf::Struct, ..), _)
|
||||
| Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _)
|
||||
| Res::SelfCtor(..)
|
||||
| Res::SelfTy(..) => {
|
||||
// Structs and Unions have only have one variant.
|
||||
Ok(VariantIdx::new(0))
|
||||
}
|
||||
_ => bug!("expected ADT path, found={:?}", res),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of fields in an ADT variant used within a pattern.
|
||||
/// Here `pat_hir_id` is the HirId of the pattern itself.
|
||||
fn total_fields_in_adt_variant(
|
||||
&self,
|
||||
pat_hir_id: hir::HirId,
|
||||
variant_index: VariantIdx,
|
||||
span: Span,
|
||||
) -> McResult<usize> {
|
||||
let ty = self.tables.node_type(pat_hir_id);
|
||||
match ty.kind {
|
||||
ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()),
|
||||
_ => {
|
||||
self.tcx()
|
||||
.sess
|
||||
.delay_span_bug(span, "struct or tuple struct pattern not applied to an ADT");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the total number of fields in a tuple used within a Tuple pattern.
|
||||
/// Here `pat_hir_id` is the HirId of the pattern itself.
|
||||
fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult<usize> {
|
||||
let ty = self.tables.node_type(pat_hir_id);
|
||||
match ty.kind {
|
||||
ty::Tuple(substs) => Ok(substs.len()),
|
||||
_ => {
|
||||
self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple");
|
||||
return Err(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(#19596) This is a workaround, but there should be a better way to do this
|
||||
fn cat_pattern_<F>(
|
||||
&self,
|
||||
@ -679,20 +777,54 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
op(&place_with_id, pat);
|
||||
|
||||
match pat.kind {
|
||||
PatKind::TupleStruct(_, ref subpats, _) | PatKind::Tuple(ref subpats, _) => {
|
||||
// S(p1, ..., pN) or (p1, ..., pN)
|
||||
for subpat in subpats.iter() {
|
||||
PatKind::Tuple(ref subpats, dots_pos) => {
|
||||
// (p1, ..., pN)
|
||||
let total_fields = self.total_fields_in_tuple(pat.hir_id, pat.span)?;
|
||||
|
||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
|
||||
let subpat_ty = self.pat_ty_adjusted(&subpat)?;
|
||||
let sub_place = self.cat_projection(pat, place_with_id.clone(), subpat_ty);
|
||||
let projection_kind = ProjectionKind::Field(i as u32, VariantIdx::new(0));
|
||||
let sub_place =
|
||||
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
|
||||
self.cat_pattern_(sub_place, &subpat, op)?;
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Struct(_, field_pats, _) => {
|
||||
PatKind::TupleStruct(ref qpath, ref subpats, dots_pos) => {
|
||||
// S(p1, ..., pN)
|
||||
let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
|
||||
let total_fields =
|
||||
self.total_fields_in_adt_variant(pat.hir_id, variant_index, pat.span)?;
|
||||
|
||||
for (i, subpat) in subpats.iter().enumerate_and_adjust(total_fields, dots_pos) {
|
||||
let subpat_ty = self.pat_ty_adjusted(&subpat)?;
|
||||
let projection_kind = ProjectionKind::Field(i as u32, variant_index);
|
||||
let sub_place =
|
||||
self.cat_projection(pat, place_with_id.clone(), subpat_ty, projection_kind);
|
||||
self.cat_pattern_(sub_place, &subpat, op)?;
|
||||
}
|
||||
}
|
||||
|
||||
PatKind::Struct(ref qpath, field_pats, _) => {
|
||||
// S { f1: p1, ..., fN: pN }
|
||||
|
||||
let variant_index = self.variant_index_for_adt(qpath, pat.hir_id, pat.span)?;
|
||||
|
||||
for fp in field_pats {
|
||||
let field_ty = self.pat_ty_adjusted(&fp.pat)?;
|
||||
let field_place = self.cat_projection(pat, place_with_id.clone(), field_ty);
|
||||
let field_index = self
|
||||
.tables
|
||||
.field_indices()
|
||||
.get(fp.hir_id)
|
||||
.cloned()
|
||||
.expect("no index for a field");
|
||||
|
||||
let field_place = self.cat_projection(
|
||||
pat,
|
||||
place_with_id.clone(),
|
||||
field_ty,
|
||||
ProjectionKind::Field(field_index as u32, variant_index),
|
||||
);
|
||||
self.cat_pattern_(field_place, &fp.pat, op)?;
|
||||
}
|
||||
}
|
||||
@ -723,13 +855,23 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
return Err(());
|
||||
}
|
||||
};
|
||||
let elt_place = self.cat_projection(pat, place_with_id.clone(), element_ty);
|
||||
let elt_place = self.cat_projection(
|
||||
pat,
|
||||
place_with_id.clone(),
|
||||
element_ty,
|
||||
ProjectionKind::Index,
|
||||
);
|
||||
for before_pat in before {
|
||||
self.cat_pattern_(elt_place.clone(), &before_pat, op)?;
|
||||
}
|
||||
if let Some(ref slice_pat) = *slice {
|
||||
let slice_pat_ty = self.pat_ty_adjusted(&slice_pat)?;
|
||||
let slice_place = self.cat_projection(pat, place_with_id, slice_pat_ty);
|
||||
let slice_place = self.cat_projection(
|
||||
pat,
|
||||
place_with_id,
|
||||
slice_pat_ty,
|
||||
ProjectionKind::Subslice,
|
||||
);
|
||||
self.cat_pattern_(slice_place, &slice_pat, op)?;
|
||||
}
|
||||
for after_pat in after {
|
||||
|
@ -12,7 +12,7 @@ use rustc_metadata::creader::LoadedMacro;
|
||||
use rustc_middle::ty;
|
||||
use rustc_mir::const_eval::is_min_const_fn;
|
||||
use rustc_span::hygiene::MacroKind;
|
||||
use rustc_span::symbol::Symbol;
|
||||
use rustc_span::symbol::{sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
use crate::clean::{self, GetDefId, ToSource, TypeKind};
|
||||
@ -194,6 +194,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
|
||||
let generics = (cx.tcx.generics_of(did), predicates).clean(cx);
|
||||
let generics = filter_non_trait_generics(did, generics);
|
||||
let (generics, supertrait_bounds) = separate_supertrait_bounds(generics);
|
||||
let is_spotlight = load_attrs(cx, did).clean(cx).has_doc_flag(sym::spotlight);
|
||||
let is_auto = cx.tcx.trait_is_auto(did);
|
||||
clean::Trait {
|
||||
auto: auto_trait,
|
||||
@ -201,6 +202,7 @@ pub fn build_external_trait(cx: &DocContext<'_>, did: DefId) -> clean::Trait {
|
||||
generics,
|
||||
items: trait_items,
|
||||
bounds: supertrait_bounds,
|
||||
is_spotlight,
|
||||
is_auto,
|
||||
}
|
||||
}
|
||||
@ -339,6 +341,16 @@ pub fn build_impl(
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip foreign unstable traits from lists of trait implementations and
|
||||
// such. This helps prevent dependencies of the standard library, for
|
||||
// example, from getting documented as "traits `u32` implements" which
|
||||
// isn't really too helpful.
|
||||
if let Some(stab) = cx.tcx.lookup_stability(did) {
|
||||
if stab.level.is_unstable() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let for_ = if let Some(did) = did.as_local() {
|
||||
|
@ -1007,6 +1007,7 @@ impl Clean<FnRetTy> for hir::FnRetTy<'_> {
|
||||
impl Clean<Item> for doctree::Trait<'_> {
|
||||
fn clean(&self, cx: &DocContext<'_>) -> Item {
|
||||
let attrs = self.attrs.clean(cx);
|
||||
let is_spotlight = attrs.has_doc_flag(sym::spotlight);
|
||||
Item {
|
||||
name: Some(self.name.clean(cx)),
|
||||
attrs,
|
||||
@ -1021,6 +1022,7 @@ impl Clean<Item> for doctree::Trait<'_> {
|
||||
items: self.items.iter().map(|ti| ti.clean(cx)).collect(),
|
||||
generics: self.generics.clean(cx),
|
||||
bounds: self.bounds.clean(cx),
|
||||
is_spotlight,
|
||||
is_auto: self.is_auto.clean(cx),
|
||||
}),
|
||||
}
|
||||
|
@ -486,33 +486,6 @@ impl Attributes {
|
||||
})
|
||||
}
|
||||
|
||||
/// Enforce the format of attributes inside `#[doc(...)]`.
|
||||
pub fn check_doc_attributes(
|
||||
diagnostic: &::rustc_errors::Handler,
|
||||
mi: &ast::MetaItem,
|
||||
) -> Option<(String, String)> {
|
||||
mi.meta_item_list().and_then(|list| {
|
||||
for meta in list {
|
||||
if meta.check_name(sym::alias) {
|
||||
if !meta.is_value_str()
|
||||
|| meta
|
||||
.value_str()
|
||||
.map(|s| s.to_string())
|
||||
.unwrap_or_else(String::new)
|
||||
.is_empty()
|
||||
{
|
||||
diagnostic.span_err(
|
||||
meta.span(),
|
||||
"doc alias attribute expects a string: #[doc(alias = \"0\")]",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
}
|
||||
|
||||
pub fn has_doc_flag(&self, flag: Symbol) -> bool {
|
||||
for attr in &self.other_attrs {
|
||||
if !attr.check_name(sym::doc) {
|
||||
@ -556,7 +529,6 @@ impl Attributes {
|
||||
} else {
|
||||
if attr.check_name(sym::doc) {
|
||||
if let Some(mi) = attr.meta() {
|
||||
Attributes::check_doc_attributes(&diagnostic, &mi);
|
||||
if let Some(cfg_mi) = Attributes::extract_cfg(&mi) {
|
||||
// Extracted #[doc(cfg(...))]
|
||||
match Cfg::parse(cfg_mi) {
|
||||
@ -995,6 +967,7 @@ pub struct Trait {
|
||||
pub items: Vec<Item>,
|
||||
pub generics: Generics,
|
||||
pub bounds: Vec<GenericBound>,
|
||||
pub is_spotlight: bool,
|
||||
pub is_auto: bool,
|
||||
}
|
||||
|
||||
|
@ -5,10 +5,15 @@ use rustc_driver::abort_on_err;
|
||||
use rustc_errors::emitter::{Emitter, EmitterWriter};
|
||||
use rustc_errors::json::JsonEmitter;
|
||||
use rustc_feature::UnstableFeatures;
|
||||
use rustc_hir::def::Namespace::TypeNS;
|
||||
use rustc_hir::def::{Namespace::TypeNS, Res};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::{
|
||||
intravisit::{self, NestedVisitorMap, Visitor},
|
||||
Path,
|
||||
};
|
||||
use rustc_interface::interface;
|
||||
use rustc_middle::hir::map::Map;
|
||||
use rustc_middle::middle::cstore::CrateStore;
|
||||
use rustc_middle::middle::privacy::AccessLevels;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
@ -372,7 +377,35 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
crate_name,
|
||||
lint_caps,
|
||||
register_lints: None,
|
||||
override_queries: None,
|
||||
override_queries: Some(|_sess, providers, _external_providers| {
|
||||
// Most lints will require typechecking, so just don't run them.
|
||||
providers.lint_mod = |_, _| {};
|
||||
// Prevent `rustc_typeck::check_crate` from calling `typeck_tables_of` on all bodies.
|
||||
providers.typeck_item_bodies = |_, _| {};
|
||||
// hack so that `used_trait_imports` won't try to call typeck_tables_of
|
||||
providers.used_trait_imports = |_, _| {
|
||||
lazy_static! {
|
||||
static ref EMPTY_SET: FxHashSet<LocalDefId> = FxHashSet::default();
|
||||
}
|
||||
&EMPTY_SET
|
||||
};
|
||||
// In case typeck does end up being called, don't ICE in case there were name resolution errors
|
||||
providers.typeck_tables_of = move |tcx, def_id| {
|
||||
// Closures' tables come from their outermost function,
|
||||
// as they are part of the same "inference environment".
|
||||
// This avoids emitting errors for the parent twice (see similar code in `typeck_tables_of_with_fallback`)
|
||||
let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local();
|
||||
if outer_def_id != def_id {
|
||||
return tcx.typeck_tables_of(outer_def_id);
|
||||
}
|
||||
|
||||
let hir = tcx.hir();
|
||||
let body = hir.body(hir.body_owned_by(hir.as_local_hir_id(def_id)));
|
||||
debug!("visiting body for {:?}", def_id);
|
||||
EmitIgnoredResolutionErrors::new(tcx).visit_body(body);
|
||||
(rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck_tables_of)(tcx, def_id)
|
||||
};
|
||||
}),
|
||||
registry: rustc_driver::diagnostics_registry(),
|
||||
};
|
||||
|
||||
@ -416,10 +449,17 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
let mut global_ctxt = abort_on_err(queries.global_ctxt(), sess).take();
|
||||
|
||||
global_ctxt.enter(|tcx| {
|
||||
tcx.analysis(LOCAL_CRATE).ok();
|
||||
|
||||
// Abort if there were any errors so far
|
||||
sess.abort_if_errors();
|
||||
// Certain queries assume that some checks were run elsewhere
|
||||
// (see https://github.com/rust-lang/rust/pull/73566#issuecomment-656954425),
|
||||
// so type-check everything other than function bodies in this crate before running lints.
|
||||
// NOTE: this does not call `tcx.analysis()` so that we won't
|
||||
// typeck function bodies or run the default rustc lints.
|
||||
// (see `override_queries` in the `config`)
|
||||
let _ = rustc_typeck::check_crate(tcx);
|
||||
tcx.sess.abort_if_errors();
|
||||
sess.time("missing_docs", || {
|
||||
rustc_lint::check_crate(tcx, rustc_lint::builtin::MissingDoc::new);
|
||||
});
|
||||
|
||||
let access_levels = tcx.privacy_access_levels(LOCAL_CRATE);
|
||||
// Convert from a HirId set to a DefId set since we don't always have easy access
|
||||
@ -570,6 +610,62 @@ pub fn run_core(options: RustdocOptions) -> (clean::Crate, RenderInfo, RenderOpt
|
||||
})
|
||||
}
|
||||
|
||||
/// Due to https://github.com/rust-lang/rust/pull/73566,
|
||||
/// the name resolution pass may find errors that are never emitted.
|
||||
/// If typeck is called after this happens, then we'll get an ICE:
|
||||
/// 'Res::Error found but not reported'. To avoid this, emit the errors now.
|
||||
struct EmitIgnoredResolutionErrors<'tcx> {
|
||||
tcx: TyCtxt<'tcx>,
|
||||
}
|
||||
|
||||
impl<'tcx> EmitIgnoredResolutionErrors<'tcx> {
|
||||
fn new(tcx: TyCtxt<'tcx>) -> Self {
|
||||
Self { tcx }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'tcx> Visitor<'tcx> for EmitIgnoredResolutionErrors<'tcx> {
|
||||
type Map = Map<'tcx>;
|
||||
|
||||
fn nested_visit_map(&mut self) -> NestedVisitorMap<Self::Map> {
|
||||
// We need to recurse into nested closures,
|
||||
// since those will fallback to the parent for type checking.
|
||||
NestedVisitorMap::OnlyBodies(self.tcx.hir())
|
||||
}
|
||||
|
||||
fn visit_path(&mut self, path: &'tcx Path<'_>, _id: HirId) {
|
||||
debug!("visiting path {:?}", path);
|
||||
if path.res == Res::Err {
|
||||
// We have less context here than in rustc_resolve,
|
||||
// so we can only emit the name and span.
|
||||
// However we can give a hint that rustc_resolve will have more info.
|
||||
let label = format!(
|
||||
"could not resolve path `{}`",
|
||||
path.segments
|
||||
.iter()
|
||||
.map(|segment| segment.ident.as_str().to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join("::")
|
||||
);
|
||||
let mut err = rustc_errors::struct_span_err!(
|
||||
self.tcx.sess,
|
||||
path.span,
|
||||
E0433,
|
||||
"failed to resolve: {}",
|
||||
label
|
||||
);
|
||||
err.span_label(path.span, label);
|
||||
err.note("this error was originally ignored because you are running `rustdoc`");
|
||||
err.note("try running again with `rustc` or `cargo check` and you may get a more detailed error");
|
||||
err.emit();
|
||||
}
|
||||
// We could have an outer resolution that succeeded,
|
||||
// but with generic parameters that failed.
|
||||
// Recurse into the segments so we catch those too.
|
||||
intravisit::walk_path(self, path);
|
||||
}
|
||||
}
|
||||
|
||||
/// `DefId` or parameter index (`ty::ParamTy.index`) of a synthetic type parameter
|
||||
/// for `impl Trait` in argument position.
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
|
@ -37,14 +37,14 @@ impl ExternalHtml {
|
||||
let bc = format!(
|
||||
"{}{}",
|
||||
bc,
|
||||
Markdown(&m_bc, &[], id_map, codes, edition, playground).to_string()
|
||||
Markdown(&m_bc, &[], id_map, codes, edition, playground).into_string()
|
||||
);
|
||||
let ac = load_external_files(after_content, diag)?;
|
||||
let m_ac = load_external_files(md_after_content, diag)?;
|
||||
let ac = format!(
|
||||
"{}{}",
|
||||
ac,
|
||||
Markdown(&m_ac, &[], id_map, codes, edition, playground).to_string()
|
||||
Markdown(&m_ac, &[], id_map, codes, edition, playground).into_string()
|
||||
);
|
||||
Some(ExternalHtml { in_header: ih, before_content: bc, after_content: ac })
|
||||
}
|
||||
|
@ -63,10 +63,22 @@ impl Buffer {
|
||||
Buffer { for_html: false, buffer: String::new() }
|
||||
}
|
||||
|
||||
crate fn is_empty(&self) -> bool {
|
||||
self.buffer.is_empty()
|
||||
}
|
||||
|
||||
crate fn into_inner(self) -> String {
|
||||
self.buffer
|
||||
}
|
||||
|
||||
crate fn insert_str(&mut self, idx: usize, s: &str) {
|
||||
self.buffer.insert_str(idx, s);
|
||||
}
|
||||
|
||||
crate fn push_str(&mut self, s: &str) {
|
||||
self.buffer.push_str(s);
|
||||
}
|
||||
|
||||
// Intended for consumption by write! and writeln! (std::fmt) but without
|
||||
// the fmt::Result return type imposed by fmt::Write (and avoiding the trait
|
||||
// import).
|
||||
|
@ -12,15 +12,17 @@ use std::io;
|
||||
use std::io::prelude::*;
|
||||
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use rustc_parse::lexer;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::hygiene::SyntaxContext;
|
||||
use rustc_span::source_map::SourceMap;
|
||||
use rustc_span::symbol::{kw, sym};
|
||||
use rustc_span::{FileName, Span};
|
||||
use rustc_span::{BytePos, FileName, SourceFile, Span};
|
||||
|
||||
/// Highlights `src`, returning the HTML output.
|
||||
pub fn render_with_highlighting(
|
||||
src: &str,
|
||||
src: String,
|
||||
class: Option<&str>,
|
||||
playground_button: Option<&str>,
|
||||
tooltip: Option<(&str, &str)>,
|
||||
@ -38,12 +40,13 @@ pub fn render_with_highlighting(
|
||||
}
|
||||
|
||||
let sess = ParseSess::with_silent_emitter();
|
||||
let sf = sess
|
||||
let source_file = sess
|
||||
.source_map()
|
||||
.new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src.to_owned());
|
||||
.new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src);
|
||||
|
||||
let classifier_source_file = Lrc::clone(&source_file);
|
||||
let highlight_result = rustc_driver::catch_fatal_errors(|| {
|
||||
let lexer = lexer::StringReader::new(&sess, sf, None);
|
||||
let mut classifier = Classifier::new(lexer, sess.source_map());
|
||||
let mut classifier = Classifier::new(&sess, classifier_source_file);
|
||||
|
||||
let mut highlighted_source = vec![];
|
||||
if classifier.write_source(&mut highlighted_source).is_err() {
|
||||
@ -61,9 +64,17 @@ pub fn render_with_highlighting(
|
||||
write_footer(&mut out, playground_button).unwrap();
|
||||
}
|
||||
Err(()) => {
|
||||
// Get the source back out of the source map to avoid a copy in the happy path.
|
||||
let span =
|
||||
Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root());
|
||||
let src = sess
|
||||
.source_map()
|
||||
.span_to_snippet(span)
|
||||
.expect("could not retrieve snippet from artificial source file");
|
||||
|
||||
// If errors are encountered while trying to highlight, just emit
|
||||
// the unhighlighted source.
|
||||
write!(out, "<pre><code>{}</code></pre>", Escape(src)).unwrap();
|
||||
write!(out, "<pre><code>{}</code></pre>", Escape(&src)).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,10 +84,10 @@ pub fn render_with_highlighting(
|
||||
/// Processes a program (nested in the internal `lexer`), classifying strings of
|
||||
/// text by highlighting category (`Class`). Calls out to a `Writer` to write
|
||||
/// each span of text in sequence.
|
||||
struct Classifier<'a> {
|
||||
lexer: lexer::StringReader<'a>,
|
||||
struct Classifier<'sess> {
|
||||
lexer: lexer::StringReader<'sess>,
|
||||
peek_token: Option<Token>,
|
||||
source_map: &'a SourceMap,
|
||||
source_map: &'sess SourceMap,
|
||||
|
||||
// State of the classifier.
|
||||
in_attribute: bool,
|
||||
@ -154,6 +165,7 @@ impl<U: Write> Writer for U {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum HighlightError {
|
||||
LexError,
|
||||
IoError(io::Error),
|
||||
@ -165,12 +177,14 @@ impl From<io::Error> for HighlightError {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Classifier<'a> {
|
||||
fn new(lexer: lexer::StringReader<'a>, source_map: &'a SourceMap) -> Classifier<'a> {
|
||||
impl<'sess> Classifier<'sess> {
|
||||
fn new(sess: &ParseSess, source_file: Lrc<SourceFile>) -> Classifier<'_> {
|
||||
let lexer = lexer::StringReader::new(sess, source_file, None);
|
||||
|
||||
Classifier {
|
||||
lexer,
|
||||
peek_token: None,
|
||||
source_map,
|
||||
source_map: sess.source_map(),
|
||||
in_attribute: false,
|
||||
in_macro: false,
|
||||
in_macro_nonterminal: false,
|
||||
@ -209,11 +223,17 @@ impl<'a> Classifier<'a> {
|
||||
/// source.
|
||||
fn write_source<W: Writer>(&mut self, out: &mut W) -> Result<(), HighlightError> {
|
||||
loop {
|
||||
let next = self.try_next_token()?;
|
||||
let mut next = self.try_next_token()?;
|
||||
if next == token::Eof {
|
||||
break;
|
||||
}
|
||||
|
||||
// Glue any tokens that need to be glued.
|
||||
if let Some(joint) = next.glue(self.peek()?) {
|
||||
next = joint;
|
||||
let _ = self.try_next_token()?;
|
||||
}
|
||||
|
||||
self.write_token(out, next)?;
|
||||
}
|
||||
|
||||
@ -429,3 +449,6 @@ fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> {
|
||||
fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> {
|
||||
write!(out, "</pre>{}</div>\n", if let Some(button) = playground_button { button } else { "" })
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
82
src/librustdoc/html/highlight/tests.rs
Normal file
82
src/librustdoc/html/highlight/tests.rs
Normal file
@ -0,0 +1,82 @@
|
||||
use rustc_ast::attr::with_session_globals;
|
||||
use rustc_session::parse::ParseSess;
|
||||
use rustc_span::edition::Edition;
|
||||
use rustc_span::FileName;
|
||||
|
||||
use super::Classifier;
|
||||
|
||||
fn highlight(src: &str) -> String {
|
||||
let mut out = vec![];
|
||||
|
||||
with_session_globals(Edition::Edition2018, || {
|
||||
let sess = ParseSess::with_silent_emitter();
|
||||
let source_file = sess.source_map().new_source_file(
|
||||
FileName::Custom(String::from("rustdoc-highlighting")),
|
||||
src.to_owned(),
|
||||
);
|
||||
|
||||
let mut classifier = Classifier::new(&sess, source_file);
|
||||
classifier.write_source(&mut out).unwrap();
|
||||
});
|
||||
|
||||
String::from_utf8(out).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function() {
|
||||
assert_eq!(
|
||||
highlight("fn main() {}"),
|
||||
r#"<span class="kw">fn</span> <span class="ident">main</span>() {}"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn statement() {
|
||||
assert_eq!(
|
||||
highlight("let foo = true;"),
|
||||
concat!(
|
||||
r#"<span class="kw">let</span> <span class="ident">foo</span> "#,
|
||||
r#"<span class="op">=</span> <span class="bool-val">true</span>;"#,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inner_attr() {
|
||||
assert_eq!(
|
||||
highlight(r##"#![crate_type = "lib"]"##),
|
||||
concat!(
|
||||
r##"<span class="attribute">#![<span class="ident">crate_type</span> "##,
|
||||
r##"<span class="op">=</span> <span class="string">"lib"</span>]</span>"##,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn outer_attr() {
|
||||
assert_eq!(
|
||||
highlight(r##"#[cfg(target_os = "linux")]"##),
|
||||
concat!(
|
||||
r##"<span class="attribute">#[<span class="ident">cfg</span>("##,
|
||||
r##"<span class="ident">target_os</span> <span class="op">=</span> "##,
|
||||
r##"<span class="string">"linux"</span>)]</span>"##,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mac() {
|
||||
assert_eq!(
|
||||
highlight("mac!(foo bar)"),
|
||||
concat!(
|
||||
r#"<span class="macro">mac</span><span class="macro">!</span>("#,
|
||||
r#"<span class="ident">foo</span> <span class="ident">bar</span>)"#,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Regression test for #72684
|
||||
#[test]
|
||||
fn andand() {
|
||||
assert_eq!(highlight("&&"), r#"<span class="op">&&</span>"#);
|
||||
}
|
@ -13,7 +13,7 @@
|
||||
//! let s = "My *markdown* _text_";
|
||||
//! let mut id_map = IdMap::new();
|
||||
//! let md = Markdown(s, &[], &mut id_map, ErrorCodes::Yes, Edition::Edition2015, &None);
|
||||
//! let html = md.to_string();
|
||||
//! let html = md.into_string();
|
||||
//! // ... something using html
|
||||
//! ```
|
||||
|
||||
@ -292,7 +292,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
||||
|
||||
if let Some((s1, s2)) = tooltip {
|
||||
s.push_str(&highlight::render_with_highlighting(
|
||||
&text,
|
||||
text,
|
||||
Some(&format!(
|
||||
"rust-example-rendered{}",
|
||||
if ignore != Ignore::None {
|
||||
@ -313,7 +313,7 @@ impl<'a, I: Iterator<Item = Event<'a>>> Iterator for CodeBlocks<'_, 'a, I> {
|
||||
Some(Event::Html(s.into()))
|
||||
} else {
|
||||
s.push_str(&highlight::render_with_highlighting(
|
||||
&text,
|
||||
text,
|
||||
Some(&format!(
|
||||
"rust-example-rendered{}",
|
||||
if ignore != Ignore::None {
|
||||
@ -848,7 +848,7 @@ impl LangString {
|
||||
}
|
||||
|
||||
impl Markdown<'_> {
|
||||
pub fn to_string(self) -> String {
|
||||
pub fn into_string(self) -> String {
|
||||
let Markdown(md, links, mut ids, codes, edition, playground) = self;
|
||||
|
||||
// This is actually common enough to special-case
|
||||
@ -878,7 +878,7 @@ impl Markdown<'_> {
|
||||
}
|
||||
|
||||
impl MarkdownWithToc<'_> {
|
||||
pub fn to_string(self) -> String {
|
||||
pub fn into_string(self) -> String {
|
||||
let MarkdownWithToc(md, mut ids, codes, edition, playground) = self;
|
||||
|
||||
let p = Parser::new_ext(md, opts());
|
||||
@ -899,7 +899,7 @@ impl MarkdownWithToc<'_> {
|
||||
}
|
||||
|
||||
impl MarkdownHtml<'_> {
|
||||
pub fn to_string(self) -> String {
|
||||
pub fn into_string(self) -> String {
|
||||
let MarkdownHtml(md, mut ids, codes, edition, playground) = self;
|
||||
|
||||
// This is actually common enough to special-case
|
||||
@ -926,7 +926,7 @@ impl MarkdownHtml<'_> {
|
||||
}
|
||||
|
||||
impl MarkdownSummaryLine<'_> {
|
||||
pub fn to_string(self) -> String {
|
||||
pub fn into_string(self) -> String {
|
||||
let MarkdownSummaryLine(md, links) = self;
|
||||
// This is actually common enough to special-case
|
||||
if md.is_empty() {
|
||||
|
@ -134,7 +134,7 @@ fn test_header() {
|
||||
fn t(input: &str, expect: &str) {
|
||||
let mut map = IdMap::new();
|
||||
let output =
|
||||
Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
|
||||
Markdown(input, &[], &mut map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
@ -166,7 +166,8 @@ fn test_header() {
|
||||
fn test_header_ids_multiple_blocks() {
|
||||
let mut map = IdMap::new();
|
||||
fn t(map: &mut IdMap, input: &str, expect: &str) {
|
||||
let output = Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
|
||||
let output =
|
||||
Markdown(input, &[], map, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ fn test_markdown_html_escape() {
|
||||
fn t(input: &str, expect: &str) {
|
||||
let mut idmap = IdMap::new();
|
||||
let output =
|
||||
MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).to_string();
|
||||
MarkdownHtml(input, &mut idmap, ErrorCodes::Yes, DEFAULT_EDITION, &None).into_string();
|
||||
assert_eq!(output, expect, "original: {}", input);
|
||||
}
|
||||
|
||||
|
@ -1895,7 +1895,7 @@ fn render_markdown(
|
||||
cx.shared.edition,
|
||||
&cx.shared.playground
|
||||
)
|
||||
.to_string()
|
||||
.into_string()
|
||||
)
|
||||
}
|
||||
|
||||
@ -2185,7 +2185,7 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean:
|
||||
</tr>",
|
||||
name = *myitem.name.as_ref().unwrap(),
|
||||
stab_tags = stability_tags(myitem),
|
||||
docs = MarkdownSummaryLine(doc_value, &myitem.links()).to_string(),
|
||||
docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(),
|
||||
class = myitem.type_(),
|
||||
add = add,
|
||||
stab = stab.unwrap_or_else(String::new),
|
||||
@ -2278,7 +2278,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
|
||||
cx.shared.edition,
|
||||
&cx.shared.playground,
|
||||
);
|
||||
message.push_str(&format!(": {}", html.to_string()));
|
||||
message.push_str(&format!(": {}", html.into_string()));
|
||||
}
|
||||
stability.push(format!(
|
||||
"<div class='stab deprecated'><span class='emoji'>👎</span> {}</div>",
|
||||
@ -2332,7 +2332,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec<String> {
|
||||
cx.shared.edition,
|
||||
&cx.shared.playground,
|
||||
)
|
||||
.to_string()
|
||||
.into_string()
|
||||
);
|
||||
}
|
||||
|
||||
@ -2415,7 +2415,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
|
||||
write!(
|
||||
w,
|
||||
"{vis}{constness}{asyncness}{unsafety}{abi}fn \
|
||||
{name}{generics}{decl}{where_clause}</pre>",
|
||||
{name}{generics}{decl}{spotlight}{where_clause}</pre>",
|
||||
vis = it.visibility.print_with_space(),
|
||||
constness = f.header.constness.print_with_space(),
|
||||
asyncness = f.header.asyncness.print_with_space(),
|
||||
@ -2425,7 +2425,8 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func
|
||||
generics = f.generics.print(),
|
||||
where_clause = WhereClause { gens: &f.generics, indent: 0, end_newline: true },
|
||||
decl = Function { decl: &f.decl, header_len, indent: 0, asyncness: f.header.asyncness }
|
||||
.print()
|
||||
.print(),
|
||||
spotlight = spotlight_decl(&f.decl),
|
||||
);
|
||||
document(w, cx, it)
|
||||
}
|
||||
@ -2612,7 +2613,7 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait)
|
||||
let name = m.name.as_ref().unwrap();
|
||||
let item_type = m.type_();
|
||||
let id = cx.derive_id(format!("{}.{}", item_type, name));
|
||||
write!(w, "<h3 id='{id}' class='method'><code>", id = id);
|
||||
write!(w, "<h3 id='{id}' class='method'><code>", id = id,);
|
||||
render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl);
|
||||
write!(w, "</code>");
|
||||
render_stability_since(w, m, t);
|
||||
@ -2926,7 +2927,7 @@ fn render_assoc_item(
|
||||
write!(
|
||||
w,
|
||||
"{}{}{}{}{}{}{}fn <a href='{href}' class='fnname'>{name}</a>\
|
||||
{generics}{decl}{where_clause}",
|
||||
{generics}{decl}{spotlight}{where_clause}",
|
||||
if parent == ItemType::Trait { " " } else { "" },
|
||||
meth.visibility.print_with_space(),
|
||||
header.constness.print_with_space(),
|
||||
@ -2938,6 +2939,7 @@ fn render_assoc_item(
|
||||
name = name,
|
||||
generics = g.print(),
|
||||
decl = Function { decl: d, header_len, indent, asyncness: header.asyncness }.print(),
|
||||
spotlight = spotlight_decl(&d),
|
||||
where_clause = WhereClause { gens: g, indent, end_newline }
|
||||
)
|
||||
}
|
||||
@ -3559,6 +3561,62 @@ fn should_render_item(item: &clean::Item, deref_mut_: bool) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
fn spotlight_decl(decl: &clean::FnDecl) -> String {
|
||||
let mut out = Buffer::html();
|
||||
let mut trait_ = String::new();
|
||||
|
||||
if let Some(did) = decl.output.def_id() {
|
||||
let c = cache();
|
||||
if let Some(impls) = c.impls.get(&did) {
|
||||
for i in impls {
|
||||
let impl_ = i.inner_impl();
|
||||
if impl_.trait_.def_id().map_or(false, |d| c.traits[&d].is_spotlight) {
|
||||
if out.is_empty() {
|
||||
out.push_str(&format!(
|
||||
"<h3 class=\"important\">Important traits for {}</h3>\
|
||||
<code class=\"content\">",
|
||||
impl_.for_.print()
|
||||
));
|
||||
trait_.push_str(&impl_.for_.print().to_string());
|
||||
}
|
||||
|
||||
//use the "where" class here to make it small
|
||||
out.push_str(&format!(
|
||||
"<span class=\"where fmt-newline\">{}</span>",
|
||||
impl_.print()
|
||||
));
|
||||
let t_did = impl_.trait_.def_id().unwrap();
|
||||
for it in &impl_.items {
|
||||
if let clean::TypedefItem(ref tydef, _) = it.inner {
|
||||
out.push_str("<span class=\"where fmt-newline\"> ");
|
||||
assoc_type(
|
||||
&mut out,
|
||||
it,
|
||||
&[],
|
||||
Some(&tydef.type_),
|
||||
AssocItemLink::GotoSource(t_did, &FxHashSet::default()),
|
||||
"",
|
||||
);
|
||||
out.push_str(";</span>");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !out.is_empty() {
|
||||
out.insert_str(
|
||||
0,
|
||||
"<span class=\"important-traits\"><span class=\"important-traits-tooltip\">ⓘ<div class='important-traits-tooltiptext'><span class=\"docblock\">"
|
||||
|
||||
);
|
||||
out.push_str("</code></span></div></span></span>");
|
||||
}
|
||||
|
||||
out.into_inner()
|
||||
}
|
||||
|
||||
fn render_impl(
|
||||
w: &mut Buffer,
|
||||
cx: &Context,
|
||||
@ -3632,7 +3690,7 @@ fn render_impl(
|
||||
cx.shared.edition,
|
||||
&cx.shared.playground
|
||||
)
|
||||
.to_string()
|
||||
.into_string()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -3670,7 +3728,8 @@ fn render_impl(
|
||||
// Only render when the method is not static or we allow static methods
|
||||
if render_method_item {
|
||||
let id = cx.derive_id(format!("{}.{}", item_type, name));
|
||||
write!(w, "<h4 id='{}' class=\"{}{}\"><code>", id, item_type, extra_class);
|
||||
write!(w, "<h4 id='{}' class=\"{}{}\">", id, item_type, extra_class);
|
||||
write!(w, "<code>");
|
||||
render_assoc_item(w, item, link.anchor(&id), ItemType::Impl);
|
||||
write!(w, "</code>");
|
||||
render_stability_since_raw(w, item.stable_since(), outer_version);
|
||||
@ -4526,7 +4585,12 @@ fn sidebar_foreign_type(buf: &mut Buffer, it: &clean::Item) {
|
||||
|
||||
fn item_macro(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Macro) {
|
||||
wrap_into_docblock(w, |w| {
|
||||
w.write_str(&highlight::render_with_highlighting(&t.source, Some("macro"), None, None))
|
||||
w.write_str(&highlight::render_with_highlighting(
|
||||
t.source.clone(),
|
||||
Some("macro"),
|
||||
None,
|
||||
None,
|
||||
))
|
||||
});
|
||||
document(w, cx, it)
|
||||
}
|
||||
|
@ -75,7 +75,7 @@ impl<'a> SourceCollector<'a> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let contents = match fs::read_to_string(&p) {
|
||||
let mut contents = match fs::read_to_string(&p) {
|
||||
Ok(contents) => contents,
|
||||
Err(e) => {
|
||||
return Err(Error::new(e, &p));
|
||||
@ -83,8 +83,9 @@ impl<'a> SourceCollector<'a> {
|
||||
};
|
||||
|
||||
// Remove the utf-8 BOM if any
|
||||
let contents =
|
||||
if contents.starts_with("\u{feff}") { &contents[3..] } else { &contents[..] };
|
||||
if contents.starts_with("\u{feff}") {
|
||||
contents.drain(..3);
|
||||
}
|
||||
|
||||
// Create the intermediate directories
|
||||
let mut cur = self.dst.clone();
|
||||
@ -122,7 +123,7 @@ impl<'a> SourceCollector<'a> {
|
||||
&self.scx.layout,
|
||||
&page,
|
||||
"",
|
||||
|buf: &mut _| print_src(buf, &contents),
|
||||
|buf: &mut _| print_src(buf, contents),
|
||||
&self.scx.style_files,
|
||||
);
|
||||
self.scx.fs.write(&cur, v.as_bytes())?;
|
||||
@ -160,7 +161,7 @@ where
|
||||
|
||||
/// Wrapper struct to render the source code of a file. This will do things like
|
||||
/// adding line numbers to the left-hand side.
|
||||
fn print_src(buf: &mut Buffer, s: &str) {
|
||||
fn print_src(buf: &mut Buffer, s: String) {
|
||||
let lines = s.lines().count();
|
||||
let mut cols = 0;
|
||||
let mut tmp = lines;
|
||||
|
@ -2636,6 +2636,13 @@ function defocusSearchBar() {
|
||||
});
|
||||
}());
|
||||
|
||||
onEachLazy(document.getElementsByClassName("important-traits"), function(e) {
|
||||
e.onclick = function() {
|
||||
this.getElementsByClassName('important-traits-tooltiptext')[0]
|
||||
.classList.toggle("force-tooltip");
|
||||
};
|
||||
});
|
||||
|
||||
// In the search display, allows to switch between tabs.
|
||||
function printTab(nb) {
|
||||
if (nb === 0 || nb === 1 || nb === 2) {
|
||||
|
@ -146,9 +146,12 @@ code, pre, a.test-arrow {
|
||||
border-radius: 3px;
|
||||
padding: 0 0.1em;
|
||||
}
|
||||
.docblock pre code, .docblock-short pre code {
|
||||
.docblock pre code, .docblock-short pre code, .docblock code.spotlight {
|
||||
padding: 0;
|
||||
}
|
||||
.docblock code.spotlight :last-child {
|
||||
padding-bottom: 0.6em;
|
||||
}
|
||||
pre {
|
||||
padding: 14px;
|
||||
}
|
||||
@ -523,7 +526,7 @@ h4 > code, h3 > code, .invisible > code {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.content .methods > div {
|
||||
.content .methods > div:not(.important-traits) {
|
||||
margin-left: 40px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
@ -1079,10 +1082,6 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.tooltip:hover .tooltiptext {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext::after {
|
||||
content: " ";
|
||||
position: absolute;
|
||||
@ -1098,13 +1097,52 @@ h3 > .collapse-toggle, h4 > .collapse-toggle {
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.tooltip .tooltiptext {
|
||||
.important-traits-tooltip {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.important-traits:hover .important-traits-tooltiptext,
|
||||
.important-traits .important-traits-tooltiptext.force-tooltip {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.important-traits .important-traits-tooltiptext {
|
||||
display: none;
|
||||
padding: 5px 3px 3px 3px;
|
||||
border-radius: 6px;
|
||||
margin-left: 5px;
|
||||
z-index: 10;
|
||||
font-size: 16px;
|
||||
cursor: default;
|
||||
position: absolute;
|
||||
border: 1px solid;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.important-traits-tooltip::after {
|
||||
/* The margin on the tooltip does not capture hover events,
|
||||
this extends the area of hover enough so that mouse hover is not
|
||||
lost when moving the mouse to the tooltip */
|
||||
content: "\00a0\00a0\00a0";
|
||||
}
|
||||
|
||||
.important-traits .important, .important-traits .docblock {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.important-traits .docblock code.content{
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
/* Example code has the "Run" button that
|
||||
needs to be positioned relative to the pre */
|
||||
pre.rust.rust-example-rendered {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
pre.rust {
|
||||
position: relative;
|
||||
tab-size: 4;
|
||||
-moz-tab-size: 4;
|
||||
}
|
||||
@ -1144,6 +1182,18 @@ pre.rust {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.important-traits {
|
||||
cursor: pointer;
|
||||
z-index: 2;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
h4 > .important-traits {
|
||||
position: absolute;
|
||||
left: -44px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
#all-types {
|
||||
text-align: center;
|
||||
border: 1px solid;
|
||||
@ -1370,6 +1420,12 @@ pre.rust {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
h4 > .important-traits {
|
||||
position: absolute;
|
||||
left: -22px;
|
||||
top: 24px;
|
||||
}
|
||||
|
||||
#titles > div > div.count {
|
||||
float: left;
|
||||
width: 100%;
|
||||
|
@ -140,4 +140,9 @@ function createSourceSidebar() {
|
||||
});
|
||||
|
||||
main.insertBefore(sidebar, main.firstChild);
|
||||
// Focus on the current file in the source files sidebar.
|
||||
var selected_elem = sidebar.getElementsByClassName("selected")[0];
|
||||
if (typeof selected_elem !== "undefined") {
|
||||
selected_elem.focus();
|
||||
}
|
||||
}
|
||||
|
@ -394,6 +394,11 @@ pre.ignore:hover, .information:hover + pre.ignore {
|
||||
border-color: transparent #314559 transparent transparent;
|
||||
}
|
||||
|
||||
.important-traits-tooltiptext {
|
||||
background-color: #314559;
|
||||
border-color: #5c6773;
|
||||
}
|
||||
|
||||
#titles > div.selected {
|
||||
background-color: #141920 !important;
|
||||
border-bottom: 1px solid #ffb44c !important;
|
||||
|
@ -337,6 +337,11 @@ pre.ignore:hover, .information:hover + pre.ignore {
|
||||
border-color: transparent black transparent transparent;
|
||||
}
|
||||
|
||||
.important-traits-tooltiptext {
|
||||
background-color: #111;
|
||||
border-color: #777;
|
||||
}
|
||||
|
||||
#titles > div:not(.selected) {
|
||||
background-color: #252525;
|
||||
border-top-color: #252525;
|
||||
|
@ -331,6 +331,11 @@ pre.ignore:hover, .information:hover + pre.ignore {
|
||||
border-color: transparent black transparent transparent;
|
||||
}
|
||||
|
||||
.important-traits-tooltiptext {
|
||||
background-color: #eee;
|
||||
border-color: #999;
|
||||
}
|
||||
|
||||
#titles > div:not(.selected) {
|
||||
background-color: #e6e6e6;
|
||||
border-top-color: #e6e6e6;
|
||||
|
@ -15,6 +15,8 @@
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
extern crate env_logger;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate rustc_ast;
|
||||
extern crate rustc_ast_pretty;
|
||||
extern crate rustc_attr;
|
||||
@ -94,6 +96,7 @@ pub fn main() {
|
||||
32_000_000 // 32MB on other platforms
|
||||
};
|
||||
rustc_driver::set_sigpipe_handler();
|
||||
rustc_driver::install_ice_hook();
|
||||
env_logger::init_from_env("RUSTDOC_LOG");
|
||||
let res = std::thread::Builder::new()
|
||||
.stack_size(thread_stack_size)
|
||||
|
@ -68,9 +68,9 @@ pub fn render<P: AsRef<Path>>(
|
||||
let mut ids = IdMap::new();
|
||||
let error_codes = ErrorCodes::from(UnstableFeatures::from_environment().is_nightly_build());
|
||||
let text = if !options.markdown_no_toc {
|
||||
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).to_string()
|
||||
MarkdownWithToc(text, &mut ids, error_codes, edition, &playground).into_string()
|
||||
} else {
|
||||
Markdown(text, &[], &mut ids, error_codes, edition, &playground).to_string()
|
||||
Markdown(text, &[], &mut ids, error_codes, edition, &playground).into_string()
|
||||
};
|
||||
|
||||
let err = write!(
|
||||
|
@ -499,6 +499,7 @@ where
|
||||
/// [`&str`]: ../../std/primitive.str.html
|
||||
/// [slice]: ../../std/primitive.slice.html
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(spotlight)]
|
||||
pub trait Read {
|
||||
/// Pull some bytes from this source into the specified buffer, returning
|
||||
/// how many bytes were read.
|
||||
@ -1261,6 +1262,7 @@ impl Initializer {
|
||||
///
|
||||
/// [`write_all`]: #method.write_all
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[doc(spotlight)]
|
||||
pub trait Write {
|
||||
/// Write a buffer into this writer, returning how many bytes were written.
|
||||
///
|
||||
|
@ -261,6 +261,7 @@
|
||||
#![feature(doc_cfg)]
|
||||
#![feature(doc_keyword)]
|
||||
#![feature(doc_masked)]
|
||||
#![cfg_attr(not(bootstrap), feature(doc_spotlight))]
|
||||
#![feature(dropck_eyepatch)]
|
||||
#![feature(duration_constants)]
|
||||
#![feature(exact_size_is_empty)]
|
||||
|
@ -6,12 +6,13 @@
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(thread_local)]
|
||||
|
||||
// CHECK: @STATIC_VAR_1 = thread_local local_unnamed_addr global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
|
||||
// local_unnamed_addr does not appear when std is built with debug assertions.
|
||||
// CHECK: @STATIC_VAR_1 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> zeroinitializer, section "__DATA,__thread_bss", align 4
|
||||
#[no_mangle]
|
||||
#[thread_local]
|
||||
static mut STATIC_VAR_1: [u32; 8] = [0; 8];
|
||||
|
||||
// CHECK: @STATIC_VAR_2 = thread_local local_unnamed_addr global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
|
||||
// CHECK: @STATIC_VAR_2 = thread_local {{(local_unnamed_addr )?}}global <{ [32 x i8] }> <{{[^>]*}}>, section "__DATA,__thread_data", align 4
|
||||
#[no_mangle]
|
||||
#[thread_local]
|
||||
static mut STATIC_VAR_2: [u32; 8] = [4; 8];
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
// min-system-llvm-version: 9.0
|
||||
// ignore-arm
|
||||
// ignore-aarch64
|
||||
// ignore-mips
|
||||
// ignore-mips64
|
||||
// ignore-powerpc
|
||||
|
@ -1,5 +1,3 @@
|
||||
// WONTFIX(#20184) Needs landing pads (not present in stage1) or the compiler hangs.
|
||||
// ignore-stage1
|
||||
// compile-flags: -C codegen-units=2
|
||||
// ignore-emscripten
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# ignore-stage1
|
||||
|
||||
all:
|
||||
$(RUSTC) a.rs && $(RUSTC) b.rs
|
||||
$(BARE_RUSTC) c.rs -L dependency=$(TMPDIR) --extern b=$(TMPDIR)/libb.rlib \
|
||||
|
@ -1,6 +1,4 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# ignore-stage1
|
||||
|
||||
all:
|
||||
$(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs
|
||||
|
16
src/test/run-make-fulldeps/rustdoc-determinism/Makefile
Normal file
16
src/test/run-make-fulldeps/rustdoc-determinism/Makefile
Normal file
@ -0,0 +1,16 @@
|
||||
-include ../tools.mk
|
||||
|
||||
# Assert that the search index is generated deterministically, regardless of the
|
||||
# order that crates are documented in.
|
||||
|
||||
# ignore-windows
|
||||
# Uses `diff`.
|
||||
|
||||
all:
|
||||
$(RUSTDOC) foo.rs -o $(TMPDIR)/foo_first
|
||||
$(RUSTDOC) bar.rs -o $(TMPDIR)/foo_first
|
||||
|
||||
$(RUSTDOC) bar.rs -o $(TMPDIR)/bar_first
|
||||
$(RUSTDOC) foo.rs -o $(TMPDIR)/bar_first
|
||||
|
||||
diff $(TMPDIR)/foo_first/search-index.js $(TMPDIR)/bar_first/search-index.js
|
1
src/test/run-make-fulldeps/rustdoc-determinism/bar.rs
Normal file
1
src/test/run-make-fulldeps/rustdoc-determinism/bar.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct Bar;
|
1
src/test/run-make-fulldeps/rustdoc-determinism/foo.rs
Normal file
1
src/test/run-make-fulldeps/rustdoc-determinism/foo.rs
Normal file
@ -0,0 +1 @@
|
||||
pub struct Foo;
|
7
src/test/rustdoc-ui/error-in-impl-trait/README.md
Normal file
7
src/test/rustdoc-ui/error-in-impl-trait/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
Each of these needs to be in a separate file,
|
||||
because the `delay_span_bug` ICE in rustdoc won't be triggerred
|
||||
if even a single other error was emitted.
|
||||
|
||||
However, conceptually they are all testing basically the same thing.
|
||||
See https://github.com/rust-lang/rust/pull/73566#issuecomment-653689128
|
||||
for more details.
|
10
src/test/rustdoc-ui/error-in-impl-trait/async.rs
Normal file
10
src/test/rustdoc-ui/error-in-impl-trait/async.rs
Normal file
@ -0,0 +1,10 @@
|
||||
// edition:2018
|
||||
|
||||
/// This used to work with ResolveBodyWithLoop.
|
||||
/// However now that we ignore type checking instead of modifying the function body,
|
||||
/// the return type is seen as `impl Future<Output = u32>`, not a `u32`.
|
||||
/// So it no longer allows errors in the function body.
|
||||
pub async fn a() -> u32 {
|
||||
error::_in::async_fn()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/async.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/async.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::async_fn`
|
||||
--> $DIR/async.rs:8:5
|
||||
|
|
||||
LL | error::_in::async_fn()
|
||||
| ^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::async_fn`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
5
src/test/rustdoc-ui/error-in-impl-trait/closure.rs
Normal file
5
src/test/rustdoc-ui/error-in-impl-trait/closure.rs
Normal file
@ -0,0 +1,5 @@
|
||||
// manually desugared version of an `async fn` (but with a closure instead of a generator)
|
||||
pub fn a() -> impl Fn() -> u32 {
|
||||
|| content::doesnt::matter()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/closure.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `content::doesnt::matter`
|
||||
--> $DIR/closure.rs:3:8
|
||||
|
|
||||
LL | || content::doesnt::matter()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `content::doesnt::matter`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
@ -0,0 +1,7 @@
|
||||
trait ValidTrait {}
|
||||
|
||||
/// This has docs
|
||||
pub fn f() -> impl ValidTrait {
|
||||
Vec::<DoesNotExist>::new()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `DoesNotExist`
|
||||
--> $DIR/generic-argument.rs:5:11
|
||||
|
|
||||
LL | Vec::<DoesNotExist>::new()
|
||||
| ^^^^^^^^^^^^ could not resolve path `DoesNotExist`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
@ -0,0 +1,6 @@
|
||||
pub trait ValidTrait {}
|
||||
/// This returns impl trait
|
||||
pub fn g() -> impl ValidTrait {
|
||||
(|| error::_in::impl_trait::alias::nested::closure())()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
--> $DIR/impl-keyword-closure.rs:4:9
|
||||
|
|
||||
LL | (|| error::_in::impl_trait::alias::nested::closure())()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
6
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
Normal file
6
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs
Normal file
@ -0,0 +1,6 @@
|
||||
pub trait ValidTrait {}
|
||||
/// This returns impl trait
|
||||
pub fn g() -> impl ValidTrait {
|
||||
error::_in::impl_trait()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait`
|
||||
--> $DIR/impl-keyword.rs:4:5
|
||||
|
|
||||
LL | error::_in::impl_trait()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
@ -0,0 +1,10 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub trait ValidTrait {}
|
||||
type ImplTrait = impl ValidTrait;
|
||||
|
||||
/// This returns impl trait, but using a type alias
|
||||
pub fn h() -> ImplTrait {
|
||||
(|| error::_in::impl_trait::alias::nested::closure())()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
--> $DIR/trait-alias-closure.rs:8:9
|
||||
|
|
||||
LL | (|| error::_in::impl_trait::alias::nested::closure())()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias::nested::closure`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
10
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
Normal file
10
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub trait ValidTrait {}
|
||||
type ImplTrait = impl ValidTrait;
|
||||
|
||||
/// This returns impl trait, but using a type alias
|
||||
pub fn h() -> ImplTrait {
|
||||
error::_in::impl_trait::alias()
|
||||
//~^ ERROR failed to resolve
|
||||
}
|
12
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
Normal file
12
src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr
Normal file
@ -0,0 +1,12 @@
|
||||
error[E0433]: failed to resolve: could not resolve path `error::_in::impl_trait::alias`
|
||||
--> $DIR/trait-alias.rs:8:5
|
||||
|
|
||||
LL | error::_in::impl_trait::alias()
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ could not resolve path `error::_in::impl_trait::alias`
|
||||
|
|
||||
= note: this error was originally ignored because you are running `rustdoc`
|
||||
= note: try running again with `rustc` or `cargo check` and you may get a more detailed error
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0433`.
|
49
src/test/rustdoc-ui/impl-fn-nesting.rs
Normal file
49
src/test/rustdoc-ui/impl-fn-nesting.rs
Normal file
@ -0,0 +1,49 @@
|
||||
// Ensure that rustdoc gives errors for trait impls inside function bodies that don't resolve.
|
||||
// See https://github.com/rust-lang/rust/pull/73566
|
||||
pub struct ValidType;
|
||||
pub trait ValidTrait {}
|
||||
pub trait NeedsBody {
|
||||
type Item;
|
||||
fn f();
|
||||
}
|
||||
|
||||
/// This function has docs
|
||||
pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
|
||||
//~^ ERROR cannot find trait `UnknownBound` in this scope
|
||||
//~| ERROR cannot find type `UnknownType` in this scope
|
||||
impl UnknownTrait for ValidType {} //~ ERROR cannot find trait `UnknownTrait`
|
||||
impl<T: UnknownBound> UnknownTrait for T {}
|
||||
//~^ ERROR cannot find trait `UnknownBound` in this scope
|
||||
//~| ERROR cannot find trait `UnknownTrait` in this scope
|
||||
impl ValidTrait for UnknownType {}
|
||||
//~^ ERROR cannot find type `UnknownType` in this scope
|
||||
impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
|
||||
//~^ ERROR cannot find trait `UnknownBound` in this scope
|
||||
|
||||
/// This impl has documentation
|
||||
impl NeedsBody for ValidType {
|
||||
type Item = UnknownType;
|
||||
//~^ ERROR cannot find type `UnknownType` in this scope
|
||||
|
||||
/// This function has documentation
|
||||
fn f() {
|
||||
<UnknownTypeShouldBeIgnored>::a();
|
||||
content::shouldnt::matter();
|
||||
unknown_macro!();
|
||||
//~^ ERROR cannot find macro `unknown_macro` in this scope
|
||||
|
||||
/// This is documentation for a macro
|
||||
macro_rules! can_define_macros_here_too {
|
||||
() => {
|
||||
this::content::should::also::be::ignored()
|
||||
}
|
||||
}
|
||||
can_define_macros_here_too!();
|
||||
|
||||
/// This also is documented.
|
||||
pub fn doubly_nested(c: UnknownType) {
|
||||
//~^ ERROR cannot find type `UnknownType` in this scope
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
66
src/test/rustdoc-ui/impl-fn-nesting.stderr
Normal file
66
src/test/rustdoc-ui/impl-fn-nesting.stderr
Normal file
@ -0,0 +1,66 @@
|
||||
error: cannot find macro `unknown_macro` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:32:13
|
||||
|
|
||||
LL | unknown_macro!();
|
||||
| ^^^^^^^^^^^^^
|
||||
|
||||
error[E0405]: cannot find trait `UnknownBound` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:11:13
|
||||
|
|
||||
LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
|
||||
| ^^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `UnknownType` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:11:30
|
||||
|
|
||||
LL | pub fn f<B: UnknownBound>(a: UnknownType, b: B) {
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `UnknownTrait` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:14:10
|
||||
|
|
||||
LL | impl UnknownTrait for ValidType {}
|
||||
| ^^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `UnknownTrait` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:15:27
|
||||
|
|
||||
LL | impl<T: UnknownBound> UnknownTrait for T {}
|
||||
| ^^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `UnknownBound` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:15:13
|
||||
|
|
||||
LL | impl<T: UnknownBound> UnknownTrait for T {}
|
||||
| ^^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `UnknownType` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:18:25
|
||||
|
|
||||
LL | impl ValidTrait for UnknownType {}
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0405]: cannot find trait `UnknownBound` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:20:53
|
||||
|
|
||||
LL | impl ValidTrait for ValidType where ValidTrait: UnknownBound {}
|
||||
| ^^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `UnknownType` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:25:21
|
||||
|
|
||||
LL | type Item = UnknownType;
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error[E0412]: cannot find type `UnknownType` in this scope
|
||||
--> $DIR/impl-fn-nesting.rs:44:37
|
||||
|
|
||||
LL | pub fn doubly_nested(c: UnknownType) {
|
||||
| ^^^^^^^^^^^ not found in this scope
|
||||
|
||||
error: Compilation failed, aborting rustdoc
|
||||
|
||||
error: aborting due to 11 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0405, E0412.
|
||||
For more information about an error, try `rustc --explain E0405`.
|
4
src/test/rustdoc-ui/infinite-recursive-type.rs
Normal file
4
src/test/rustdoc-ui/infinite-recursive-type.rs
Normal file
@ -0,0 +1,4 @@
|
||||
enum E {
|
||||
//~^ ERROR recursive type `E` has infinite size
|
||||
V(E),
|
||||
}
|
17
src/test/rustdoc-ui/infinite-recursive-type.stderr
Normal file
17
src/test/rustdoc-ui/infinite-recursive-type.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0072]: recursive type `E` has infinite size
|
||||
--> $DIR/infinite-recursive-type.rs:1:1
|
||||
|
|
||||
LL | enum E {
|
||||
| ^^^^^^ recursive type has infinite size
|
||||
LL |
|
||||
LL | V(E),
|
||||
| - recursive without indirection
|
||||
|
|
||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `E` representable
|
||||
|
|
||||
LL | V(Box<E>),
|
||||
| ^^^^ ^
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0072`.
|
36
src/test/rustdoc/doc-spotlight.rs
Normal file
36
src/test/rustdoc/doc-spotlight.rs
Normal file
@ -0,0 +1,36 @@
|
||||
#![feature(doc_spotlight)]
|
||||
|
||||
pub struct Wrapper<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T: SomeTrait> SomeTrait for Wrapper<T> {}
|
||||
|
||||
#[doc(spotlight)]
|
||||
pub trait SomeTrait {
|
||||
// @has doc_spotlight/trait.SomeTrait.html
|
||||
// @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
|
||||
fn wrap_me(self) -> Wrapper<Self> where Self: Sized {
|
||||
Wrapper {
|
||||
inner: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SomeStruct;
|
||||
impl SomeTrait for SomeStruct {}
|
||||
|
||||
impl SomeStruct {
|
||||
// @has doc_spotlight/struct.SomeStruct.html
|
||||
// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
|
||||
// @has - '//code[@class="content"]' 'impl<T: SomeTrait> SomeTrait for Wrapper<T>'
|
||||
pub fn new() -> SomeStruct {
|
||||
SomeStruct
|
||||
}
|
||||
}
|
||||
|
||||
// @has doc_spotlight/fn.bare_fn.html
|
||||
// @has - '//code[@class="content"]' 'impl SomeTrait for SomeStruct'
|
||||
pub fn bare_fn() -> SomeStruct {
|
||||
SomeStruct
|
||||
}
|
14
src/test/rustdoc/impl-trait-alias.rs
Normal file
14
src/test/rustdoc/impl-trait-alias.rs
Normal file
@ -0,0 +1,14 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
trait MyTrait {}
|
||||
impl MyTrait for i32 {}
|
||||
|
||||
// @has impl_trait_alias/type.Foo.html 'Foo'
|
||||
/// debug type
|
||||
pub type Foo = impl MyTrait;
|
||||
|
||||
// @has impl_trait_alias/fn.foo.html 'foo'
|
||||
/// debug function
|
||||
pub fn foo() -> Foo {
|
||||
1
|
||||
}
|
9
src/test/rustdoc/macro-in-async-block.rs
Normal file
9
src/test/rustdoc/macro-in-async-block.rs
Normal file
@ -0,0 +1,9 @@
|
||||
// Regression issue for rustdoc ICE encountered in PR #72088.
|
||||
// edition:2018
|
||||
#![feature(decl_macro)]
|
||||
|
||||
fn main() {
|
||||
async {
|
||||
macro m() {}
|
||||
};
|
||||
}
|
@ -6,4 +6,11 @@ fn main() {
|
||||
|| {
|
||||
macro m() {}
|
||||
};
|
||||
|
||||
let _ = || {
|
||||
macro n() {}
|
||||
};
|
||||
|
||||
let cond = true;
|
||||
let _ = || if cond { macro n() {} } else { panic!() };
|
||||
}
|
||||
|
15
src/test/rustdoc/return-impl-trait.rs
Normal file
15
src/test/rustdoc/return-impl-trait.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(type_alias_impl_trait)]
|
||||
|
||||
pub trait Backend {}
|
||||
|
||||
impl Backend for () {}
|
||||
|
||||
pub struct Module<T>(T);
|
||||
|
||||
pub type BackendImpl = impl Backend;
|
||||
|
||||
// @has return_impl_trait/fn.make_module.html
|
||||
/// Documentation
|
||||
pub fn make_module() -> Module<BackendImpl> {
|
||||
Module(())
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(doc_alias)]
|
||||
|
||||
#[doc(alias = "foo")] // ok!
|
@ -1,17 +1,17 @@
|
||||
error: doc alias attribute expects a string: #[doc(alias = "0")]
|
||||
--> $DIR/check-doc-alias-attr.rs:6:7
|
||||
--> $DIR/check-doc-alias-attr.rs:7:7
|
||||
|
|
||||
LL | #[doc(alias)]
|
||||
| ^^^^^
|
||||
|
||||
error: doc alias attribute expects a string: #[doc(alias = "0")]
|
||||
--> $DIR/check-doc-alias-attr.rs:7:7
|
||||
--> $DIR/check-doc-alias-attr.rs:8:7
|
||||
|
|
||||
LL | #[doc(alias = 0)]
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: doc alias attribute expects a string: #[doc(alias = "0")]
|
||||
--> $DIR/check-doc-alias-attr.rs:8:7
|
||||
--> $DIR/check-doc-alias-attr.rs:9:7
|
||||
|
|
||||
LL | #[doc(alias("bar"))]
|
||||
| ^^^^^^^^^^^^
|
@ -0,0 +1,15 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
|
||||
// Currently, const parameters cannot depend on other generic parameters,
|
||||
// as our current implementation can't really support this.
|
||||
//
|
||||
// We may want to lift this restriction in the future.
|
||||
|
||||
pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
|
||||
//~^ ERROR: the type of const parameters must not depend on other generic parameters
|
||||
|
||||
pub struct SelfDependent<const N: [u8; N]>;
|
||||
//~^ ERROR: the type of const parameters must not depend on other generic parameters
|
||||
|
||||
fn main() {}
|
@ -0,0 +1,24 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/const-param-type-depends-on-const-param.rs:9:52
|
||||
|
|
||||
LL | pub struct Dependent<const N: usize, const X: [u8; N]>([(); N]);
|
||||
| ^ the type must not depend on the parameter `N`
|
||||
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/const-param-type-depends-on-const-param.rs:12:40
|
||||
|
|
||||
LL | pub struct SelfDependent<const N: [u8; N]>;
|
||||
| ^ the type must not depend on the parameter `N`
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/const-param-type-depends-on-const-param.rs:1:12
|
||||
|
|
||||
LL | #![feature(const_generics)]
|
||||
| ^^^^^^^^^^^^^^
|
||||
|
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0770`.
|
@ -1,6 +1,6 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct B<T, const N: T>(PhantomData<[T; N]>); //~ ERROR const generics are unstable
|
||||
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
|
||||
//~^ ERROR the type of const parameters must not depend on other generic parameters
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,3 +1,9 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
|
||||
|
|
||||
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
|
||||
| ^ the type must not depend on the parameter `T`
|
||||
|
||||
error[E0658]: const generics are unstable
|
||||
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:19
|
||||
|
|
||||
@ -7,15 +13,7 @@ LL | struct B<T, const N: T>(PhantomData<[T; N]>);
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
= help: add `#![feature(const_generics)]` to the crate attributes to enable
|
||||
|
||||
error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
|
||||
--> $DIR/const-param-type-depends-on-type-param-ungated.rs:3:22
|
||||
|
|
||||
LL | struct B<T, const N: T>(PhantomData<[T; N]>);
|
||||
| ^ `T` may not derive both `PartialEq` and `Eq`
|
||||
|
|
||||
= note: it is not currently possible to use a type parameter as the type of a const parameter
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0658, E0741.
|
||||
Some errors have detailed explanations: E0658, E0770.
|
||||
For more information about an error, try `rustc --explain E0658`.
|
||||
|
@ -1,12 +1,13 @@
|
||||
#![feature(const_generics)]
|
||||
//~^ WARN the feature `const_generics` is incomplete
|
||||
|
||||
// Currently, const parameters cannot depend on type parameters, because there is no way to
|
||||
// enforce the structural-match property on an arbitrary type parameter. This restriction
|
||||
// may be relaxed in the future. See https://github.com/rust-lang/rfcs/pull/2000 for more
|
||||
// details.
|
||||
// Currently, const parameters cannot depend on other generic parameters,
|
||||
// as our current implementation can't really support this.
|
||||
//
|
||||
// We may want to lift this restriction in the future.
|
||||
|
||||
pub struct Dependent<T, const X: T>([(); X]);
|
||||
//~^ ERROR `T` is not guaranteed to `#[derive(PartialEq, Eq)]`
|
||||
//~^ ERROR: the type of const parameters must not depend on other generic parameters
|
||||
//~| ERROR: parameter `T` is never used
|
||||
|
||||
fn main() {}
|
||||
|
@ -1,3 +1,9 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
|
||||
|
|
||||
LL | pub struct Dependent<T, const X: T>([(); X]);
|
||||
| ^ the type must not depend on the parameter `T`
|
||||
|
||||
warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:1:12
|
||||
|
|
||||
@ -7,14 +13,15 @@ LL | #![feature(const_generics)]
|
||||
= note: `#[warn(incomplete_features)]` on by default
|
||||
= note: see issue #44580 <https://github.com/rust-lang/rust/issues/44580> for more information
|
||||
|
||||
error[E0741]: `T` is not guaranteed to `#[derive(PartialEq, Eq)]`, so may not be used as the type of a const parameter
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:9:34
|
||||
error[E0392]: parameter `T` is never used
|
||||
--> $DIR/const-param-type-depends-on-type-param.rs:9:22
|
||||
|
|
||||
LL | pub struct Dependent<T, const X: T>([(); X]);
|
||||
| ^ `T` may not derive both `PartialEq` and `Eq`
|
||||
| ^ unused parameter
|
||||
|
|
||||
= note: it is not currently possible to use a type parameter as the type of a const parameter
|
||||
= help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData`
|
||||
|
||||
error: aborting due to previous error; 1 warning emitted
|
||||
error: aborting due to 2 previous errors; 1 warning emitted
|
||||
|
||||
For more information about this error, try `rustc --explain E0741`.
|
||||
Some errors have detailed explanations: E0392, E0770.
|
||||
For more information about an error, try `rustc --explain E0392`.
|
||||
|
@ -0,0 +1,14 @@
|
||||
#![feature(const_generics)]
|
||||
|
||||
// All of these three items must be in `lib2` to reproduce the error
|
||||
|
||||
pub trait TypeFn {
|
||||
type Output;
|
||||
}
|
||||
|
||||
pub struct GenericType<const B: i8>;
|
||||
|
||||
// Removing the braces around `42` resolves the crash
|
||||
impl TypeFn for GenericType<{ 42 }> {
|
||||
type Output = ();
|
||||
}
|
18
src/test/ui/const-generics/issues/issue-68596.rs
Normal file
18
src/test/ui/const-generics/issues/issue-68596.rs
Normal file
@ -0,0 +1,18 @@
|
||||
// check-pass
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
pub struct S(u8);
|
||||
|
||||
impl S {
|
||||
pub fn get<const A: u8>(&self) -> &u8 {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
const A: u8 = 5;
|
||||
let s = S(0);
|
||||
|
||||
s.get::<A>();
|
||||
}
|
10
src/test/ui/const-generics/issues/issue-71169.rs
Normal file
10
src/test/ui/const-generics/issues/issue-71169.rs
Normal file
@ -0,0 +1,10 @@
|
||||
#![feature(const_generics)]
|
||||
#![allow(incomplete_features)]
|
||||
|
||||
fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
|
||||
//~^ ERROR the type of const parameters must not
|
||||
fn main() {
|
||||
const DATA: [u8; 4] = *b"ABCD";
|
||||
foo::<4, DATA>();
|
||||
//~^ ERROR constant expression depends on
|
||||
}
|
17
src/test/ui/const-generics/issues/issue-71169.stderr
Normal file
17
src/test/ui/const-generics/issues/issue-71169.stderr
Normal file
@ -0,0 +1,17 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/issue-71169.rs:4:43
|
||||
|
|
||||
LL | fn foo<const LEN: usize, const DATA: [u8; LEN]>() {}
|
||||
| ^^^ the type must not depend on the parameter `LEN`
|
||||
|
||||
error: constant expression depends on a generic parameter
|
||||
--> $DIR/issue-71169.rs:8:14
|
||||
|
|
||||
LL | foo::<4, DATA>();
|
||||
| ^^^^
|
||||
|
|
||||
= note: this may fail depending on what value the parameter takes
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0770`.
|
@ -12,6 +12,7 @@ unsafe extern "C" fn pass(args: PassArg) {
|
||||
impl Test {
|
||||
pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
|
||||
//~^ ERROR: using function pointers as const generic parameters is forbidden
|
||||
//~| ERROR: the type of const parameters must not depend on other generic parameters
|
||||
self.0 = Self::trampiline::<Args, IDX, FN> as _
|
||||
}
|
||||
|
||||
@ -20,6 +21,7 @@ impl Test {
|
||||
const IDX: usize,
|
||||
const FN: unsafe extern "C" fn(Args),
|
||||
//~^ ERROR: using function pointers as const generic parameters is forbidden
|
||||
//~| ERROR: the type of const parameters must not depend on other generic parameters
|
||||
>(
|
||||
args: Args,
|
||||
) {
|
||||
|
@ -1,3 +1,15 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/issue-71381.rs:13:82
|
||||
|
|
||||
LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "C" fn(Args)>(&self) {
|
||||
| ^^^^ the type must not depend on the parameter `Args`
|
||||
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/issue-71381.rs:22:40
|
||||
|
|
||||
LL | const FN: unsafe extern "C" fn(Args),
|
||||
| ^^^^ the type must not depend on the parameter `Args`
|
||||
|
||||
error: using function pointers as const generic parameters is forbidden
|
||||
--> $DIR/issue-71381.rs:13:61
|
||||
|
|
||||
@ -5,10 +17,11 @@ LL | pub fn call_me<Args: Sized, const IDX: usize, const FN: unsafe extern "
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: using function pointers as const generic parameters is forbidden
|
||||
--> $DIR/issue-71381.rs:21:19
|
||||
--> $DIR/issue-71381.rs:22:19
|
||||
|
|
||||
LL | const FN: unsafe extern "C" fn(Args),
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0770`.
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
fn func<A, const F: fn(inner: A)>(outer: A) {
|
||||
//~^ ERROR: using function pointers as const generic parameters is forbidden
|
||||
//~| ERROR: the type of const parameters must not depend on other generic parameters
|
||||
F(outer);
|
||||
}
|
||||
|
||||
|
@ -1,8 +1,15 @@
|
||||
error[E0770]: the type of const parameters must not depend on other generic parameters
|
||||
--> $DIR/issue-71611.rs:4:31
|
||||
|
|
||||
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
|
||||
| ^ the type must not depend on the parameter `A`
|
||||
|
||||
error: using function pointers as const generic parameters is forbidden
|
||||
--> $DIR/issue-71611.rs:4:21
|
||||
|
|
||||
LL | fn func<A, const F: fn(inner: A)>(outer: A) {
|
||||
| ^^^^^^^^^^^^
|
||||
|
||||
error: aborting due to previous error
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0770`.
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user