diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 29421895a9482..99140bec17029 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 diff --git a/RELEASES.md b/RELEASES.md index 7bac14cb41534..f36cdee0975a0 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -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`, `Rc` now implement `From>`, and `Box` now diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index 8545ec15d3280..0b3b77f217dbd 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -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..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 diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index eea674f2b84b9..d16c2a9d0342c 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -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 diff --git a/src/doc/unstable-book/src/language-features/doc-spotlight.md b/src/doc/unstable-book/src/language-features/doc-spotlight.md new file mode 100644 index 0000000000000..8117755fef1c8 --- /dev/null +++ b/src/doc/unstable-book/src/language-features/doc-spotlight.md @@ -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 diff --git a/src/liballoc/collections/btree/map.rs b/src/liballoc/collections/btree/map.rs index f3781db1cf784..bf5748739d470 100644 --- a/src/liballoc/collections/btree/map.rs +++ b/src/liballoc/collections/btree/map.rs @@ -151,7 +151,7 @@ impl Clone for BTreeMap { 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 Clone for BTreeMap { } 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 Clone for BTreeMap { // 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 { - self.ensure_root_is_owned(); - match search::search_tree::, K, (), K>(self.root.as_mut()?.as_mut(), &key) { + let root = Self::ensure_is_owned(&mut self.root); + match search::search_tree::, 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 BTreeMap { // 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 BTreeMap { #[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 BTreeMap { } fn from_sorted_iter>(&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 BTreeMap { self.length += 1; } + Self::fix_right_edge(root) } - fn fix_right_edge(&mut self) { + fn fix_right_edge(root: &mut node::Root) { // 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 BTreeMap { } 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 BTreeMap { } } - 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 BTreeMap { 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 BTreeMap { } /// 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 { - 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>) -> &mut node::Root { + root.get_or_insert_with(node::Root::new_leaf) } } @@ -2825,6 +2757,65 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter } } +impl node::Root { + /// 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, K, V, marker::Internal>, marker::Edge>, bool, usize), diff --git a/src/liballoc/collections/btree/node.rs b/src/liballoc/collections/btree/node.rs index ce74d4f8ee688..f7bd64608d63c 100644 --- a/src/liballoc/collections/btree/node.rs +++ b/src/liballoc/collections/btree/node.rs @@ -153,6 +153,11 @@ unsafe impl Sync for Root {} unsafe impl Send for Root {} impl Root { + /// 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 } diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index abf461338d80a..733ebdc0e97f2 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -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"] diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs index 540a8cfb290b3..45b636b0089b2 100644 --- a/src/libcore/intrinsics.rs +++ b/src/libcore/intrinsics.rs @@ -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); diff --git a/src/libcore/iter/traits/iterator.rs b/src/libcore/iter/traits/iterator.rs index ce4be973140e5..692eed80c0252 100644 --- a/src/libcore/iter/traits/iterator.rs +++ b/src/libcore/iter/traits/iterator.rs @@ -92,6 +92,7 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} 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. diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index 88991dea7d43e..c2dc3e5985f34 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -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)] diff --git a/src/librustc_ast_passes/feature_gate.rs b/src/librustc_ast_passes/feature_gate.rs index a7b0c9cf81be6..b424c8afb3471 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/src/librustc_ast_passes/feature_gate.rs @@ -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 ); diff --git a/src/librustc_error_codes/error_codes.rs b/src/librustc_error_codes/error_codes.rs index 60aa12b0511c7..6160450d76676 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/src/librustc_error_codes/error_codes.rs @@ -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 diff --git a/src/librustc_error_codes/error_codes/E0671.md b/src/librustc_error_codes/error_codes/E0671.md index 449fb8ffc8945..a993ce826a737 100644 --- a/src/librustc_error_codes/error_codes/E0671.md +++ b/src/librustc_error_codes/error_codes/E0671.md @@ -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 { // error diff --git a/src/librustc_error_codes/error_codes/E0705.md b/src/librustc_error_codes/error_codes/E0705.md index 8fa09fe8e725b..1edd47de4cbbd 100644 --- a/src/librustc_error_codes/error_codes/E0705.md +++ b/src/librustc_error_codes/error_codes/E0705.md @@ -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: diff --git a/src/librustc_error_codes/error_codes/E0710.md b/src/librustc_error_codes/error_codes/E0710.md index d9cefe2a6da72..b7037ea611ba2 100644 --- a/src/librustc_error_codes/error_codes/E0710.md +++ b/src/librustc_error_codes/error_codes/E0710.md @@ -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: diff --git a/src/librustc_error_codes/error_codes/E0770.md b/src/librustc_error_codes/error_codes/E0770.md new file mode 100644 index 0000000000000..278bf9b907b24 --- /dev/null +++ b/src/librustc_error_codes/error_codes/E0770.md @@ -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() {} // error! +``` + +To fix this error, use a concrete type for the const parameter: + +``` +#![feature(const_generics)] +fn foo() {} +``` diff --git a/src/librustc_feature/active.rs b/src/librustc_feature/active.rs index 0da3693af4fb6..d7c310a8b4c8b 100644 --- a/src/librustc_feature/active.rs +++ b/src/librustc_feature/active.rs @@ -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), diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index 07b489a756267..9204f778a24b9 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -2687,7 +2687,7 @@ pub enum Node<'hir> { Crate(&'hir CrateItem<'hir>), } -impl Node<'_> { +impl<'hir> Node<'hir> { pub fn ident(&self) -> Option { 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), diff --git a/src/librustc_interface/passes.rs b/src/librustc_interface/passes.rs index af4397075bb60..f1b9fafc78158 100644 --- a/src/librustc_interface/passes.rs +++ b/src/librustc_interface/passes.rs @@ -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); } diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index fbe3377d87500..237a5a64f8bf8 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -484,7 +484,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { lint: &'static lint::Lint, source_info: SourceInfo, message: &'static str, - panic: AssertKind, + panic: AssertKind, ) -> 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 { + Val(T), + Underscore, + } + impl std::fmt::Debug for DbgVal { + 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) => { diff --git a/src/librustc_passes/check_attr.rs b/src/librustc_passes/check_attr.rs index 46aa5a4dcdff5..3e63a63d9d0f9 100644 --- a/src/librustc_passes/check_attr.rs +++ b/src/librustc_passes/check_attr.rs @@ -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, diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 4f25b948eb66e..575049c6bac2f 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -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, diff --git a/src/librustc_resolve/late.rs b/src/librustc_resolve/late.rs index c165a601408fd..ed88e54969215 100644 --- a/src/librustc_resolve/late.rs +++ b/src/librustc_resolve/late.rs @@ -123,6 +123,10 @@ crate enum RibKind<'a> { /// from the default of a type parameter because they're not declared /// before said type parameter. Also see the `visit_generics` override. ForwardTyParamBanRibKind, + + /// We are inside of the type of a const parameter. Can't refer to any + /// parameters. + ConstParamTyRibKind, } impl RibKind<'_> { @@ -135,7 +139,8 @@ impl RibKind<'_> { | FnItemRibKind | ConstantItemRibKind | ModuleRibKind(_) - | MacroDefinition(_) => false, + | MacroDefinition(_) + | ConstParamTyRibKind => false, AssocItemRibKind | ItemRibKind(_) | ForwardTyParamBanRibKind => true, } } @@ -394,13 +399,23 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// Fields used to add information to diagnostic errors. diagnostic_metadata: DiagnosticMetadata<'ast>, + + /// State used to know whether to ignore resolution errors for function bodies. + /// + /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. + /// In most cases this will be `None`, in which case errors will always be reported. + /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. + in_func_body: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); + // Always report errors in items we just entered. + let old_ignore = replace(&mut self.in_func_body, false); self.resolve_item(item); + self.in_func_body = old_ignore; self.diagnostic_metadata.current_item = prev; } fn visit_arm(&mut self, arm: &'ast Arm) { @@ -497,6 +512,9 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { visit::walk_fn_ret_ty(this, &declaration.output); + // Ignore errors in function bodies if this is rustdoc + // Be sure not to set this until the function signature has been resolved. + let previous_state = replace(&mut this.in_func_body, true); // Resolve the function body, potentially inside the body of an async closure match fn_kind { FnKind::Fn(.., body) => walk_list!(this, visit_block, body), @@ -504,6 +522,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { }; debug!("(resolving function) leaving function"); + this.in_func_body = previous_state; }) }); self.diagnostic_metadata.current_function = previous_value; @@ -562,7 +581,11 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { for bound in ¶m.bounds { self.visit_param_bound(bound); } + self.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind)); + self.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind)); self.visit_ty(ty); + self.ribs[TypeNS].pop().unwrap(); + self.ribs[ValueNS].pop().unwrap(); } } } @@ -644,6 +667,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { label_ribs: Vec::new(), current_trait_ref: None, diagnostic_metadata: DiagnosticMetadata::default(), + // errors at module scope should always be reported + in_func_body: false, } } @@ -757,7 +782,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { return if self.is_label_valid_from_rib(i) { Some(*id) } else { - self.r.report_error( + self.report_error( original_span, ResolutionError::UnreachableLabel { name: label.name, @@ -775,7 +800,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { suggestion = suggestion.or_else(|| self.suggestion_for_label_in_rib(i, label)); } - self.r.report_error( + self.report_error( original_span, ResolutionError::UndeclaredLabel { name: label.name, suggestion }, ); @@ -798,7 +823,8 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { | ItemRibKind(..) | ConstantItemRibKind | ModuleRibKind(..) - | ForwardTyParamBanRibKind => { + | ForwardTyParamBanRibKind + | ConstParamTyRibKind => { return false; } } @@ -833,7 +859,11 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { }; let report_error = |this: &Self, ns| { let what = if ns == TypeNS { "type parameters" } else { "local variables" }; - this.r.session.span_err(ident.span, &format!("imports cannot refer to {}", what)); + if this.should_report_errs() { + this.r + .session + .span_err(ident.span, &format!("imports cannot refer to {}", what)); + } }; for &ns in nss { @@ -1008,7 +1038,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if seen_bindings.contains_key(&ident) { let span = seen_bindings.get(&ident).unwrap(); let err = ResolutionError::NameAlreadyUsedInParameterList(ident.name, *span); - self.r.report_error(param.ident.span, err); + self.report_error(param.ident.span, err); } seen_bindings.entry(ident).or_insert(param.ident.span); @@ -1274,7 +1304,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .is_err() { let path = &self.current_trait_ref.as_ref().unwrap().1.path; - self.r.report_error(span, err(ident.name, &path_names_to_string(path))); + self.report_error(span, err(ident.name, &path_names_to_string(path))); } } } @@ -1289,6 +1319,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { } fn resolve_local(&mut self, local: &'ast Local) { + debug!("resolving local ({:?})", local); // Resolve the type. walk_list!(self, visit_ty, &local.ty); @@ -1390,7 +1421,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if inconsistent_vars.contains_key(name) { v.could_be_path = false; } - self.r.report_error( + self.report_error( *v.origin.iter().next().unwrap(), ResolutionError::VariableNotBoundInPattern(v), ); @@ -1400,7 +1431,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut inconsistent_vars = inconsistent_vars.iter().collect::>(); 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| { - 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 }; - - this.r.use_injections.push(UseError { err, candidates, def_id, instead, suggestion }); + 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 }; + + 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, diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index a265c15c18bc9..c3686ca4899bc 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -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. diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 75f588918a020..ccb6ccb57fa40 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -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, diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index b8e26fc487140..f6ebf8b56bd4c 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -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 diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs index 4354996614b2a..17212187e6a01 100644 --- a/src/librustc_typeck/collect.rs +++ b/src/librustc_typeck/collect.rs @@ -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 Visitor<'v> for AnonConstInParamListDetector { + type Map = intravisit::ErasedMap<'v>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + 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)`, + // and the types of const parameters, e.g. `struct V();`. + 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)); diff --git a/src/librustc_typeck/expr_use_visitor.rs b/src/librustc_typeck/expr_use_visitor.rs index 4e5ef4329c2c6..1be32729b1ee5 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/src/librustc_typeck/expr_use_visitor.rs @@ -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); } diff --git a/src/librustc_typeck/mem_categorization.rs b/src/librustc_typeck/mem_categorization.rs index ac42ce80689ec..70fe2c2cda512 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/src/librustc_typeck/mem_categorization.rs @@ -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` 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 { + 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 { + 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 { + 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_( &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 { diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index 78628b198a3c3..491daa80e5c85 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -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() { diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03d6853494cfc..8a4ee91df405f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1007,6 +1007,7 @@ impl Clean for hir::FnRetTy<'_> { impl Clean 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 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), }), } diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index c9ae67ded0a3f..6a03722cd0802 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -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, pub generics: Generics, pub bounds: Vec, + pub is_spotlight: bool, pub is_auto: bool, } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index a222920c7d292..00315675fafe3 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -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 = 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 { + // 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::>() + .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)] diff --git a/src/librustdoc/externalfiles.rs b/src/librustdoc/externalfiles.rs index 8b5a3a2ba6131..c8121d39d0f8f 100644 --- a/src/librustdoc/externalfiles.rs +++ b/src/librustdoc/externalfiles.rs @@ -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 }) } diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index a453a8b3dcb2a..0d8284029afc7 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -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). diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index c4bc73770a76b..d4302d0cb546b 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -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, "
{}
", Escape(src)).unwrap(); + write!(out, "
{}
", 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, - source_map: &'a SourceMap, + source_map: &'sess SourceMap, // State of the classifier. in_attribute: bool, @@ -154,6 +165,7 @@ impl Writer for U { } } +#[derive(Debug)] enum HighlightError { LexError, IoError(io::Error), @@ -165,12 +177,14 @@ impl From 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) -> 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(&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, "{}\n", if let Some(button) = playground_button { button } else { "" }) } + +#[cfg(test)] +mod tests; diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs new file mode 100644 index 0000000000000..01b25fd6be4ac --- /dev/null +++ b/src/librustdoc/html/highlight/tests.rs @@ -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#"fn main() {}"#, + ); +} + +#[test] +fn statement() { + assert_eq!( + highlight("let foo = true;"), + concat!( + r#"let foo "#, + r#"= true;"#, + ), + ); +} + +#[test] +fn inner_attr() { + assert_eq!( + highlight(r##"#![crate_type = "lib"]"##), + concat!( + r##"#![crate_type "##, + r##"= "lib"]"##, + ), + ); +} + +#[test] +fn outer_attr() { + assert_eq!( + highlight(r##"#[cfg(target_os = "linux")]"##), + concat!( + r##"#[cfg("##, + r##"target_os = "##, + r##""linux")]"##, + ), + ); +} + +#[test] +fn mac() { + assert_eq!( + highlight("mac!(foo bar)"), + concat!( + r#"mac!("#, + r#"foo bar)"#, + ), + ); +} + +// Regression test for #72684 +#[test] +fn andand() { + assert_eq!(highlight("&&"), r#"&&"#); +} diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index a0f8eb04e2efb..4cfd81ffbce9d 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -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>> 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>> 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() { diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index bf0451a1d9d65..783977d285dc4 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -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); } diff --git a/src/librustdoc/html/render.rs b/src/librustdoc/html/render.rs index 9fa3f6cc39610..31e35125dac57 100644 --- a/src/librustdoc/html/render.rs +++ b/src/librustdoc/html/render.rs @@ -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: ", 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 { cx.shared.edition, &cx.shared.playground, ); - message.push_str(&format!(": {}", html.to_string())); + message.push_str(&format!(": {}", html.into_string())); } stability.push(format!( "
👎 {}
", @@ -2332,7 +2332,7 @@ fn short_stability(item: &clean::Item, cx: &Context) -> Vec { 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}", + {name}{generics}{decl}{spotlight}{where_clause}", 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, "

", id = id); + write!(w, "

", id = id,); render_assoc_item(w, m, AssocItemLink::Anchor(Some(&id)), ItemType::Impl); write!(w, ""); render_stability_since(w, m, t); @@ -2926,7 +2927,7 @@ fn render_assoc_item( write!( w, "{}{}{}{}{}{}{}fn {name}\ - {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!( + "

Important traits for {}

\ + ", + impl_.for_.print() + )); + trait_.push_str(&impl_.for_.print().to_string()); + } + + //use the "where" class here to make it small + out.push_str(&format!( + "{}", + 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(" "); + assoc_type( + &mut out, + it, + &[], + Some(&tydef.type_), + AssocItemLink::GotoSource(t_did, &FxHashSet::default()), + "", + ); + out.push_str(";"); + } + } + } + } + } + } + + if !out.is_empty() { + out.insert_str( + 0, + "
" + + ); + out.push_str("
"); + } + + 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, "

", id, item_type, extra_class); + write!(w, "

", id, item_type, extra_class); + write!(w, ""); render_assoc_item(w, item, link.anchor(&id), ItemType::Impl); write!(w, ""); 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) } diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index 03f79b931868b..e3215921f125c 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -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; diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 336c691ac1c24..082f9cca064f1 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -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) { diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 15a0c76ceeafb..f5551446bf220 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -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; } -pre.rust { +.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 { 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%; diff --git a/src/librustdoc/html/static/source-script.js b/src/librustdoc/html/static/source-script.js index cfbfe6675f52b..6805f2a266f09 100644 --- a/src/librustdoc/html/static/source-script.js +++ b/src/librustdoc/html/static/source-script.js @@ -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(); + } } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index bc21c28750fd8..b436997da5816 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -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; diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index 41dcb5c24507c..f4ca67f8540a9 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -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; diff --git a/src/librustdoc/html/static/themes/light.css b/src/librustdoc/html/static/themes/light.css index 386fe2398e63a..b5a0ba4775c24 100644 --- a/src/librustdoc/html/static/themes/light.css +++ b/src/librustdoc/html/static/themes/light.css @@ -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; diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 57151e2b20002..cbf53d52ef009 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -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) diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index e0753bcd70f29..89d184e35cb06 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -68,9 +68,9 @@ pub fn render>( 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!( diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 717d2868abf98..d5af4f25102d1 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -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. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 4fd5e238eea11..cbc24009a949a 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -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)] diff --git a/src/test/codegen/issue-44056-macos-tls-align.rs b/src/test/codegen/issue-44056-macos-tls-align.rs index eee59be629bb6..2270eca501428 100644 --- a/src/test/codegen/issue-44056-macos-tls-align.rs +++ b/src/test/codegen/issue-44056-macos-tls-align.rs @@ -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]; diff --git a/src/test/codegen/repr-transparent-aggregates-1.rs b/src/test/codegen/repr-transparent-aggregates-1.rs index c23c57c8c5900..59f29e756fc9a 100644 --- a/src/test/codegen/repr-transparent-aggregates-1.rs +++ b/src/test/codegen/repr-transparent-aggregates-1.rs @@ -3,6 +3,7 @@ // min-system-llvm-version: 9.0 // ignore-arm +// ignore-aarch64 // ignore-mips // ignore-mips64 // ignore-powerpc diff --git a/src/test/compile-fail/asm-src-loc-codegen-units.rs b/src/test/compile-fail/asm-src-loc-codegen-units.rs index c9415aed930d5..5b8690c3b98ce 100644 --- a/src/test/compile-fail/asm-src-loc-codegen-units.rs +++ b/src/test/compile-fail/asm-src-loc-codegen-units.rs @@ -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 diff --git a/src/test/run-make-fulldeps/issue-37839/Makefile b/src/test/run-make-fulldeps/issue-37839/Makefile index c405d5c74d7af..f17ce537fb813 100644 --- a/src/test/run-make-fulldeps/issue-37839/Makefile +++ b/src/test/run-make-fulldeps/issue-37839/Makefile @@ -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 \ diff --git a/src/test/run-make-fulldeps/issue-37893/Makefile b/src/test/run-make-fulldeps/issue-37893/Makefile index df58d4f5d9486..27b69baf97787 100644 --- a/src/test/run-make-fulldeps/issue-37893/Makefile +++ b/src/test/run-make-fulldeps/issue-37893/Makefile @@ -1,6 +1,4 @@ -include ../tools.mk -# ignore-stage1 - all: $(RUSTC) a.rs && $(RUSTC) b.rs && $(RUSTC) c.rs diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/Makefile b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile new file mode 100644 index 0000000000000..0534c2c383145 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/Makefile @@ -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 diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs new file mode 100644 index 0000000000000..ca05a6a9076c2 --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/bar.rs @@ -0,0 +1 @@ +pub struct Bar; diff --git a/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs new file mode 100644 index 0000000000000..4a835673a596b --- /dev/null +++ b/src/test/run-make-fulldeps/rustdoc-determinism/foo.rs @@ -0,0 +1 @@ +pub struct Foo; diff --git a/src/test/rustdoc-ui/error-in-impl-trait/README.md b/src/test/rustdoc-ui/error-in-impl-trait/README.md new file mode 100644 index 0000000000000..1176a4a8c4cf8 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/README.md @@ -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. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.rs b/src/test/rustdoc-ui/error-in-impl-trait/async.rs new file mode 100644 index 0000000000000..112a2c494a5c2 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.rs @@ -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`, 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 +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/async.stderr b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr new file mode 100644 index 0000000000000..086db1be72274 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/async.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs new file mode 100644 index 0000000000000..df40c121d579e --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.rs @@ -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 +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr new file mode 100644 index 0000000000000..4ee9c4d1f438d --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/closure.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs new file mode 100644 index 0000000000000..0ccf2e3866fc9 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.rs @@ -0,0 +1,7 @@ +trait ValidTrait {} + +/// This has docs +pub fn f() -> impl ValidTrait { + Vec::::new() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr new file mode 100644 index 0000000000000..72716c258dc1e --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/generic-argument.stderr @@ -0,0 +1,12 @@ +error[E0433]: failed to resolve: could not resolve path `DoesNotExist` + --> $DIR/generic-argument.rs:5:11 + | +LL | Vec::::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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs new file mode 100644 index 0000000000000..399fb827517fa --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.rs @@ -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 +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr new file mode 100644 index 0000000000000..55f9b609a1105 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword-closure.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs new file mode 100644 index 0000000000000..24b5734dbd0bf --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.rs @@ -0,0 +1,6 @@ +pub trait ValidTrait {} +/// This returns impl trait +pub fn g() -> impl ValidTrait { + error::_in::impl_trait() + //~^ ERROR failed to resolve +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr new file mode 100644 index 0000000000000..3257079f94219 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/impl-keyword.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs new file mode 100644 index 0000000000000..1498fa4f890d0 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.rs @@ -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 +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr new file mode 100644 index 0000000000000..84b28139dbcd5 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias-closure.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs new file mode 100644 index 0000000000000..cf9bc48c7f872 --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.rs @@ -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 +} diff --git a/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr new file mode 100644 index 0000000000000..9be6a3d8d6bba --- /dev/null +++ b/src/test/rustdoc-ui/error-in-impl-trait/trait-alias.stderr @@ -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`. diff --git a/src/test/rustdoc-ui/impl-fn-nesting.rs b/src/test/rustdoc-ui/impl-fn-nesting.rs new file mode 100644 index 0000000000000..a927f6bd79976 --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.rs @@ -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(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 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() { + ::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 + } + } + } +} diff --git a/src/test/rustdoc-ui/impl-fn-nesting.stderr b/src/test/rustdoc-ui/impl-fn-nesting.stderr new file mode 100644 index 0000000000000..608749af895ed --- /dev/null +++ b/src/test/rustdoc-ui/impl-fn-nesting.stderr @@ -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(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(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 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 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`. diff --git a/src/test/rustdoc-ui/infinite-recursive-type.rs b/src/test/rustdoc-ui/infinite-recursive-type.rs new file mode 100644 index 0000000000000..32793fc4f76c0 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.rs @@ -0,0 +1,4 @@ +enum E { +//~^ ERROR recursive type `E` has infinite size + V(E), +} diff --git a/src/test/rustdoc-ui/infinite-recursive-type.stderr b/src/test/rustdoc-ui/infinite-recursive-type.stderr new file mode 100644 index 0000000000000..897445f200cb7 --- /dev/null +++ b/src/test/rustdoc-ui/infinite-recursive-type.stderr @@ -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), + | ^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/rustdoc/doc-spotlight.rs b/src/test/rustdoc/doc-spotlight.rs new file mode 100644 index 0000000000000..ddd46c3c2155f --- /dev/null +++ b/src/test/rustdoc/doc-spotlight.rs @@ -0,0 +1,36 @@ +#![feature(doc_spotlight)] + +pub struct Wrapper { + inner: T, +} + +impl SomeTrait for Wrapper {} + +#[doc(spotlight)] +pub trait SomeTrait { + // @has doc_spotlight/trait.SomeTrait.html + // @has - '//code[@class="content"]' 'impl SomeTrait for Wrapper' + fn wrap_me(self) -> Wrapper 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 SomeTrait for Wrapper' + 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 +} diff --git a/src/test/rustdoc/impl-trait-alias.rs b/src/test/rustdoc/impl-trait-alias.rs new file mode 100644 index 0000000000000..54c3f856ddb3c --- /dev/null +++ b/src/test/rustdoc/impl-trait-alias.rs @@ -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 +} diff --git a/src/test/rustdoc/macro-in-async-block.rs b/src/test/rustdoc/macro-in-async-block.rs new file mode 100644 index 0000000000000..b4aaacf7b3d40 --- /dev/null +++ b/src/test/rustdoc/macro-in-async-block.rs @@ -0,0 +1,9 @@ +// Regression issue for rustdoc ICE encountered in PR #72088. +// edition:2018 +#![feature(decl_macro)] + +fn main() { + async { + macro m() {} + }; +} diff --git a/src/test/rustdoc/macro-in-closure.rs b/src/test/rustdoc/macro-in-closure.rs index 298ff601de89f..b4411d927e271 100644 --- a/src/test/rustdoc/macro-in-closure.rs +++ b/src/test/rustdoc/macro-in-closure.rs @@ -6,4 +6,11 @@ fn main() { || { macro m() {} }; + + let _ = || { + macro n() {} + }; + + let cond = true; + let _ = || if cond { macro n() {} } else { panic!() }; } diff --git a/src/test/rustdoc/return-impl-trait.rs b/src/test/rustdoc/return-impl-trait.rs new file mode 100644 index 0000000000000..1ccf5ac46119a --- /dev/null +++ b/src/test/rustdoc/return-impl-trait.rs @@ -0,0 +1,15 @@ +#![feature(type_alias_impl_trait)] + +pub trait Backend {} + +impl Backend for () {} + +pub struct Module(T); + +pub type BackendImpl = impl Backend; + +// @has return_impl_trait/fn.make_module.html +/// Documentation +pub fn make_module() -> Module { + Module(()) +} diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs similarity index 88% rename from src/test/rustdoc-ui/check-doc-alias-attr.rs rename to src/test/ui/check-doc-alias-attr.rs index 2f01099107d9e..b02cc1a4545b1 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -1,3 +1,4 @@ +#![crate_type = "lib"] #![feature(doc_alias)] #[doc(alias = "foo")] // ok! diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr similarity index 92% rename from src/test/rustdoc-ui/check-doc-alias-attr.stderr rename to src/test/ui/check-doc-alias-attr.stderr index 480acc821aaa8..268230ab44a0a 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -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"))] | ^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs new file mode 100644 index 0000000000000..5aa3617d1d7e0 --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.rs @@ -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([(); N]); +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +pub struct SelfDependent; +//~^ ERROR: the type of const parameters must not depend on other generic parameters + +fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr new file mode 100644 index 0000000000000..f6606aea726ad --- /dev/null +++ b/src/test/ui/const-generics/const-param-type-depends-on-const-param.stderr @@ -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([(); 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; + | ^ 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 for more information + +error: aborting due to 2 previous errors; 1 warning emitted + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs index 86ab8075896aa..db15ececfa436 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.rs @@ -1,6 +1,6 @@ use std::marker::PhantomData; struct B(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() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr index 92a7edf96bccb..35996e833610d 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param-ungated.stderr @@ -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(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(PhantomData<[T; N]>); = note: see issue #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(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`. diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs index 654e36df37e98..7fe04a43412a1 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.rs @@ -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([(); 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() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr index ed05264161e53..d081dcbbc7a4e 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.stderr @@ -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([(); 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 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([(); 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`. diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs new file mode 100644 index 0000000000000..59a4d345cbccb --- /dev/null +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -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; + +// Removing the braces around `42` resolves the crash +impl TypeFn for GenericType<{ 42 }> { + type Output = (); +} diff --git a/src/test/ui/const-generics/issues/issue-68596.rs b/src/test/ui/const-generics/issues/issue-68596.rs new file mode 100644 index 0000000000000..1f96e7d3b410a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68596.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +pub struct S(u8); + +impl S { + pub fn get(&self) -> &u8 { + &self.0 + } +} + +fn main() { + const A: u8 = 5; + let s = S(0); + + s.get::(); +} diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs new file mode 100644 index 0000000000000..943a16cfcd6a7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -0,0 +1,10 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn foo() {} +//~^ ERROR the type of const parameters must not +fn main() { + const DATA: [u8; 4] = *b"ABCD"; + foo::<4, DATA>(); + //~^ ERROR constant expression depends on +} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.stderr new file mode 100644 index 0000000000000..6d4cf4027c146 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.stderr @@ -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() {} + | ^^^ 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`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index c32bd2847f837..08f9482394218 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -12,6 +12,7 @@ unsafe extern "C" fn pass(args: PassArg) { impl Test { pub fn call_me(&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:: 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, ) { diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.stderr index 6bb776fcfc017..fd4ebe3dead81 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.stderr @@ -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(&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 $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`. diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 64a049e743faf..06ff38dec66c7 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -3,6 +3,7 @@ fn func(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); } diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.stderr index 9a7bf1c0a8841..e2c9f22361ebe 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.stderr @@ -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(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(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`. diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs new file mode 100644 index 0000000000000..aea4de39f79ce --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -0,0 +1,8 @@ +// check-pass +// aux-build:const_generic_issues_lib.rs +extern crate const_generic_issues_lib as lib2; +fn unused_function( + _: as lib2::TypeFn>::Output +) {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs new file mode 100644 index 0000000000000..05e1513bb75df --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +const LEN: usize = 1024; + +fn hoge() {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73508.rs b/src/test/ui/const-generics/issues/issue-73508.rs new file mode 100644 index 0000000000000..ba2e2a38e7470 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.rs @@ -0,0 +1,6 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +pub const fn func_name() {} +//~^ ERROR using raw pointers + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73508.stderr b/src/test/ui/const-generics/issues/issue-73508.stderr new file mode 100644 index 0000000000000..23ad1818b6f37 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.stderr @@ -0,0 +1,17 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/issue-73508.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:3:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error; 1 warning emitted + diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs new file mode 100644 index 0000000000000..2f427ef3a27dc --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -0,0 +1,9 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn test() {} + +struct Foo; + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74255.rs b/src/test/ui/const-generics/issues/issue-74255.rs new file mode 100644 index 0000000000000..55ccf57dc99c3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74255.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(dead_code, incomplete_features)] + +#[derive(PartialEq, Eq)] +enum IceEnum { + Variant +} + +struct IceStruct; + +impl IceStruct { + fn ice_struct_fn() {} +} + +fn main() { + IceStruct::ice_struct_fn::<{IceEnum::Variant}>(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs new file mode 100644 index 0000000000000..a3d059591987c --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs @@ -0,0 +1,28 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct X; + +impl X { + pub fn getn(&self) -> [u8; N] { + getn::() + } +} + +fn getn() -> [u8; N] { + unsafe { + std::mem::zeroed() + } +} + +fn main() { + // works + let [a,b,c] = getn::<3>(); + + // cannot pattern-match on an array without a fixed length + let [a,b,c] = X.getn::<3>(); + + // mismatched types, expected array `[u8; 3]` found array `[u8; _]` + let arr: [u8; 3] = X.getn::<3>(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs new file mode 100644 index 0000000000000..c53a149fa8d46 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs @@ -0,0 +1,22 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct A; + +struct X; + +impl X { + fn inner() -> A { + outer::() + } +} + +fn outer() -> A { + A +} + +fn main() { + let i: A<3usize> = outer::<3usize>(); + let o: A<3usize> = X::inner::<3usize>(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-70217.rs b/src/test/ui/const-generics/type-dependent/issue-70217.rs new file mode 100644 index 0000000000000..caa611cbd797f --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-70217.rs @@ -0,0 +1,16 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Struct; + +impl Struct { + fn method(&self) {} +} + +fn test(x: Struct) { + Struct::::method::(&x); + x.method::(); +} + +fn main() {} diff --git a/src/test/ui/const-generics/type-dependent/issue-70586.rs b/src/test/ui/const-generics/type-dependent/issue-70586.rs new file mode 100644 index 0000000000000..5a0888506eb1e --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-70586.rs @@ -0,0 +1,33 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +use std::marker::PhantomData; + +// This namespace is necessary for the ICE to trigger +struct Namespace; + +impl Namespace { + pub fn const_chunks_exact() -> ConstChunksExact<'static, T, N> { + ConstChunksExact { inner: PhantomData } + } +} + + +#[derive(Debug)] +pub struct ConstChunksExact<'a, T, const N: usize> { + inner: PhantomData<&'a T> +} + +impl <'a, T, const N: usize> Iterator for ConstChunksExact<'a, T, { N }> { + type Item = &'a [T; N]; + + fn next(&mut self) -> Option { + unreachable!() + } +} + +fn main() { + let mut chunks = Namespace::const_chunks_exact::(); + let _next: &[i32; 3] = chunks.next().unwrap(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.rs b/src/test/ui/const-generics/type-dependent/issue-71348.rs new file mode 100644 index 0000000000000..ec22dcdf60b46 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71348.rs @@ -0,0 +1,35 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +struct Foo { + i: i32, +} + +trait Get<'a, const N: &'static str> { + type Target: 'a; + + fn get(&'a self) -> &'a Self::Target; +} + +impl Foo { + fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + where + Self: Get<'a, N>, + { + self.get() + } +} + +impl<'a> Get<'a, "int"> for Foo { + type Target = i32; + + fn get(&'a self) -> &'a Self::Target { + &self.i + } +} + +fn main() { + let foo = Foo { i: 123 }; + assert_eq!(foo.ask::<"int">(), &123); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-71805.rs b/src/test/ui/const-generics/type-dependent/issue-71805.rs new file mode 100644 index 0000000000000..6823d780aefa9 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71805.rs @@ -0,0 +1,41 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +use std::mem::MaybeUninit; + +trait CollectSlice<'a>: Iterator { + fn inner_array(&mut self) -> [Self::Item; N]; + + fn collect_array(&mut self) -> [Self::Item; N] { + let result = self.inner_array(); + assert!(self.next().is_none()); + result + } +} + +impl<'a, I: ?Sized> CollectSlice<'a> for I +where + I: Iterator, +{ + fn inner_array(&mut self) -> [Self::Item; N] { + let mut result: [MaybeUninit; N] = + unsafe { MaybeUninit::uninit().assume_init() }; + + let mut count = 0; + for (dest, item) in result.iter_mut().zip(self) { + *dest = MaybeUninit::new(item); + count += 1; + } + + assert_eq!(N, count); + + let temp_ptr: *const [MaybeUninit; N] = &result; + unsafe { std::ptr::read(temp_ptr as *const [Self::Item; N]) } + } +} + +fn main() { + let mut foos = [0u64; 9].iter().cloned(); + let _bar: [u64; 9] = foos.collect_array::<9_usize>(); +} diff --git a/src/test/ui/const-generics/type-dependent/issue-73730.rs b/src/test/ui/const-generics/type-dependent/issue-73730.rs new file mode 100644 index 0000000000000..d90cc50ddc447 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-73730.rs @@ -0,0 +1,17 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Foo<'a, A>: Iterator { + fn bar(&mut self) -> *const [A; N]; +} + +impl<'a, A, I: ?Sized> Foo<'a, A> for I where I: Iterator { + fn bar(&mut self) -> *const [A; N] { + std::ptr::null() + } +} + +fn main() { + (0_u8 .. 10).bar::<10_usize>(); +} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs index 5f2d5e80243fe..d19cf00eb9ce4 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.rs @@ -1,9 +1,12 @@ // check-pass +// compile-flags: --crate-type lib + +#![warn(unconditional_panic)] + pub struct Fixed64(i64); -pub fn div(f: Fixed64) { - f.0 / 0; +// HACK: this test passes only because this is a const fn that is written to metadata +pub const fn div(f: Fixed64) { + f.0 / 0; //~ WARN will panic at runtime } - -fn main() {} diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr new file mode 100644 index 0000000000000..e2a3e4db8abd1 --- /dev/null +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -0,0 +1,14 @@ +warning: this operation will panic at runtime + --> $DIR/ice-assert-fail-div-by-zero.rs:11:5 + | +LL | f.0 / 0; + | ^^^^^^^ attempt to divide _ by zero + | +note: the lint level is defined here + --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 + | +LL | #![warn(unconditional_panic)] + | ^^^^^^^^^^^^^^^^^^^ + +warning: 1 warning emitted + diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs new file mode 100644 index 0000000000000..452b45b34456b --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.rs @@ -0,0 +1,4 @@ +#[doc(spotlight)] //~ ERROR: `#[doc(spotlight)]` is experimental +trait SomeTrait {} + +fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr new file mode 100644 index 0000000000000..010d74054a412 --- /dev/null +++ b/src/test/ui/feature-gates/feature-gate-doc_spotlight.stderr @@ -0,0 +1,12 @@ +error[E0658]: `#[doc(spotlight)]` is experimental + --> $DIR/feature-gate-doc_spotlight.rs:1:1 + | +LL | #[doc(spotlight)] + | ^^^^^^^^^^^^^^^^^ + | + = note: see issue #45040 for more information + = help: add `#![feature(doc_spotlight)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/tools/error_index_generator/main.rs b/src/tools/error_index_generator/main.rs index 9aea859999cea..c4292d041d051 100644 --- a/src/tools/error_index_generator/main.rs +++ b/src/tools/error_index_generator/main.rs @@ -127,7 +127,7 @@ impl Formatter for HTMLFormatter { DEFAULT_EDITION, &Some(playground) ) - .to_string() + .into_string() )? } None => write!(output, "

No description.

\n")?,