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:
bors 2020-07-16 19:01:48 +00:00
commit 5c9e5df3a0
118 changed files with 1951 additions and 285 deletions

View File

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

View File

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

View File

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

View File

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

View 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

View File

@ -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),

View File

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

View File

@ -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"]

View File

@ -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);

View File

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

View File

@ -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)]

View File

@ -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
);

View File

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

View File

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

View File

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

View File

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

View 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>() {}
```

View File

@ -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),

View File

@ -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),

View File

@ -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);
}

View File

@ -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) => {

View File

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

View File

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

View File

@ -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 &param.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,

View File

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

View File

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

View File

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

View File

@ -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));

View File

@ -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);
}

View File

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

View File

@ -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() {

View File

@ -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),
}),
}

View File

@ -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,
}

View File

@ -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)]

View File

@ -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 })
}

View File

@ -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).

View File

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

View 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">&quot;lib&quot;</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">&quot;linux&quot;</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">&amp;&amp;</span>"#);
}

View File

@ -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() {

View File

@ -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);
}

View File

@ -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)
}

View File

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

View File

@ -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) {

View File

@ -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%;

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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!(

View File

@ -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.
///

View File

@ -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)]

View File

@ -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];

View File

@ -3,6 +3,7 @@
// min-system-llvm-version: 9.0
// ignore-arm
// ignore-aarch64
// ignore-mips
// ignore-mips64
// ignore-powerpc

View File

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

View File

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

View File

@ -1,6 +1,4 @@
-include ../tools.mk
# ignore-stage1
all:
$(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs

View 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

View File

@ -0,0 +1 @@
pub struct Bar;

View File

@ -0,0 +1 @@
pub struct Foo;

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

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

View 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`.

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

View 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`.

View File

@ -0,0 +1,7 @@
trait ValidTrait {}
/// This has docs
pub fn f() -> impl ValidTrait {
Vec::<DoesNotExist>::new()
//~^ ERROR failed to resolve
}

View File

@ -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`.

View File

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

View File

@ -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`.

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

View 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`.

View 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::nested::closure())()
//~^ ERROR failed to resolve
}

View File

@ -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`.

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

View 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`.

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

View 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`.

View File

@ -0,0 +1,4 @@
enum E {
//~^ ERROR recursive type `E` has infinite size
V(E),
}

View 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`.

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

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

View File

@ -0,0 +1,9 @@
// Regression issue for rustdoc ICE encountered in PR #72088.
// edition:2018
#![feature(decl_macro)]
fn main() {
async {
macro m() {}
};
}

View File

@ -6,4 +6,11 @@ fn main() {
|| {
macro m() {}
};
let _ = || {
macro n() {}
};
let cond = true;
let _ = || if cond { macro n() {} } else { panic!() };
}

View 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(())
}

View File

@ -1,3 +1,4 @@
#![crate_type = "lib"]
#![feature(doc_alias)]
#[doc(alias = "foo")] // ok!

View File

@ -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"))]
| ^^^^^^^^^^^^

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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() {}

View File

@ -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`.

View File

@ -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 = ();
}

View 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>();
}

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

View 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`.

View File

@ -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,
) {

View File

@ -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`.

View File

@ -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);
}

View File

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