rustdoc: fix & clean up handling of cross-crate higher-ranked parameters
Preparatory work for the refactoring planned in #113015 (for correctness & maintainability).
---
1. Render the higher-ranked parameters of cross-crate function pointer types **(*)**.
2. Replace occurrences of `collect_referenced_late_bound_regions()` (CRLBR) with `bound_vars()`.
The former is quite problematic and the use of the latter allows us to yank a lot of hacky code **(†)**
as you can tell from the diff! :)
3. Add support for cross-crate higher-ranked types (`#![feature(non_lifetime_binders)]`).
We were previously ICE'ing on them (see `inline_cross/non_lifetime_binders.rs`).
---
**(*)**: Extracted from test `inline_cross/fn-type.rs`:
```diff
- fn(_: &'z fn(_: &'b str), _: &'a ()) -> &'a ()
+ for<'z, 'a, '_unused> fn(_: &'z for<'b> fn(_: &'b str), _: &'a ()) -> &'a ()
```
**(†)**: It returns an `FxHashSet` which isn't *predictable* or *stable* wrt. source code (`.rmeta`) changes. To elaborate, the ordering of late-bound regions doesn't necessarily reflect the ordering found in the source code. It does seem to be stable across compilations but modifying the source code of the to-be-documented crates (like adding or renaming items) may result in a different order:
<details><summary>Example</summary>
Let's assume that we're documenting the cross-crate re-export of `produce` from the code below. On `master`, rustdoc would render the list of binders as `for<'x, 'y, 'z>`. However, once you add back the functions `a`–`l`, it would be rendered as `for<'z, 'y, 'x>` (reverse order)! Results may vary. `bound_vars()` fixes this as it returns them in source order.
```rs
// pub fn a() {}
// pub fn b() {}
// pub fn c() {}
// pub fn d() {}
// pub fn e() {}
// pub fn f() {}
// pub fn g() {}
// pub fn h() {}
// pub fn i() {}
// pub fn j() {}
// pub fn k() {}
// pub fn l() {}
pub fn produce() -> impl for<'x, 'y, 'z> Trait<'z, 'y, 'x> {}
pub trait Trait<'a, 'b, 'c> {}
impl Trait<'_, '_, '_> for () {}
```
</details>
Further, as the name suggests, CRLBR only collects *referenced* regions and thus we drop unused binders. `bound_vars()` contains unused binders on the other hand. Let's stay closer to the source where possible and keep unused binders.
Lastly, using `bound_vars()` allows us to get rid of
* the deduplication and alphabetical sorting hack in `simplify.rs`
* the weird field `bound_params` on `EqPredicate`
both of which were introduced by me in #102707 back when I didn't know better.
To illustrate, let's look at the cross-crate bound `T: for<'a, 'b> Trait<A<'a> = (), B<'b> = ()>`.
* With CRLBR + `EqPredicate.bound_params`, *before* bounds simplification we would have the bounds `T: Trait`, `for<'a> <T as Trait>::A<'a> == ()` and `for<'b> <T as Trait>::B<'b> == ()` which required us to merge `for<>`, `for<'a>` and `for<'b>` into `for<'a, 'b>` in a deterministic manner and without introducing duplicate binders.
* With `bound_vars()`, we now have the bounds `for<'a, b> T: Trait`, `<T as Trait>::A<'a> == ()` and `<T as Trait>::B<'b> == ()` before bound simplification similar to rustc itself. This obviously no longer requires any funny merging of `for<>`s. On top of that `for<'a, 'b>` is guaranteed to be in source order.
rustdoc: Render private fields in tuple struct as `/* private fields */`
Reopening of https://github.com/rust-lang/rust/pull/110552. All that was missing was a test for the different cases so I added it into the second commit.
Description from the original PR:
> I've gotten some feedback that the current rustdoc rendering of...
>
> ```
> struct HasPrivateFields(_);
> ```
>
> ...is confusing, and I agree with that feedback, especially compared to the field struct case:
>
> ```
> struct HasPrivateFields { /* private fields */ }
> ```
>
> So this PR makes it so that when all of the fields of a tuple variant are private, just render it with the `/* private fields */` comment. We can't *always* render it like that, for example when there's a mix of private and public fields.
cc ````@jsha````
r? ````@notriddle````
Skip rendering metadata strings from include_str!/include_bytes!
The const rendering code in rustdoc completely ignores consts from expansions, but the compiler was rendering all consts. So some consts (namely those from `include_bytes!`) were rendered then ignored.
Most of the diff here is from moving `print_const_expr` from rustdoc into `rustc_hir_pretty` so that it can be used in rustdoc and when building rmeta files.
This let's us handle a multitude of things for free:
- #[doc(hidden)]
- private fields/variants
- --document-private-items
- --document-hidden-items
And correct in the process the determination of "has stripped items" by
doing the same logic done by other ones.
Remake of "List matching impls on type aliases"
* 4b1d13d984
* 6f552c800b
* 2ce7cd906b
Partially reverts "Fix infinite loop when retrieving impls for
type alias", but keeps the test case.
This version of the PR avoids the infinite loop by structurally
matching types instead of using full unification. This version
does not support type alias trait bounds, but the compiler does
not enforce those anyway
(https://github.com/rust-lang/rust/issues/21903).
Rustdoc: Add unstable --no-html-source flag
Fixes https://github.com/rust-lang/rust/issues/115060.
This is the equivalent of `#![doc(no_html_source)]` but on the command-line. It disables the generation of the source pages (and of the links pointing to them as well).
The motivation behind this is to enable to reduce documentation size when generating it in some locations without enforcing this to end users or adding a new feature to enable/disable the crate attribute.
r? `@notriddle`
It lints against features that are inteded to be internal to the
compiler and standard library. Implements MCP #596.
We allow `internal_features` in the standard library and compiler as those
use many features and this _is_ the standard library from the "internal to the compiler and
standard library" after all.
Marking some features as internal wasn't exactly the most scientific approach, I just marked some
mostly obvious features. While there is a categorization in the macro,
it's not very well upheld (should probably be fixed in another PR).
We always pass `-Ainternal_features` in the testsuite
About 400 UI tests and several other tests use internal features.
Instead of throwing the attribute on each one, just always allow them.
There's nothing wrong with testing internal features^^
[rustdoc] If re-export is private, get the next item until a public one is found or expose the private item directly
Fixes#81141.
If we have:
```rust
use Private as Something;
pub fn foo() -> Something {}
```
Then `Something` will be replaced by `Private`.
r? `@notriddle`
rustdoc: fix cross-crate `impl Sized` & `impl ?Sized`
Previously, cross-crate impl-Trait (APIT, RPIT, etc.) that only consists of a single `Sized` bound (modulo outlives-bounds) and ones that are `?Sized` were incorrectly rendered. To give you a taste (before vs. after):
```diff
- fn sized(x: impl ) -> impl
+ fn sized(x: impl Sized) -> impl Sized
- fn sized_outlives<'a>(x: impl 'a) -> impl 'a
+ fn sized_outlives<'a>(x: impl Sized + 'a) -> impl Sized + 'a
- fn maybe_sized(x: &impl ) -> &impl
+ fn maybe_sized(x: &impl ?Sized) -> &impl ?Sized
- fn debug_maybe_sized(x: &impl Debug) -> &impl ?Sized + Debug
+ fn debug_maybe_sized(x: &(impl Debug + ?Sized)) -> &(impl Debug + ?Sized)
```
Moreover, we now surround impl-Trait that has multiple bounds with parentheses if they're the pointee of a reference or raw pointer type. This affects both local and cross-crate docs. The current output isn't correct (rustc would emit the error *ambiguous `+` in a type* if we fed the rendered code back to it).
---
Best reviewed commit by commit :)
`@rustbot` label A-cross-crate-reexports
Fix missing attribute merge on glob foreign re-exports
Fixes https://github.com/rust-lang/rust/issues/113982.
The attributes were not merged with the import's in case of glob re-export of foreign items.
r? `@notriddle`
fix intra-doc links on nested `use` and `extern crate` items
This PR fixes two rustdoc ICEs that happen if there are any intra-doc links on nested `use` or `extern crate` items, for example:
```rust
/// Re-export [`fmt`] and [`io`].
pub use std::{fmt, io}; // "nested" use = use with braces
/// Re-export [`std`].
pub extern crate std;
```
Nested use items were incorrectly considered private and therefore didn't have their intra-doc links resolved. I fixed this by always resolving intra-doc links for nested `use` items that are declared `pub`.
<details>
During AST->HIR lowering, nested `use` items are desugared like this:
```rust
pub use std::{}; // "list stem"
pub use std::fmt;
pub use std::io;
```
Each of these HIR nodes has it's own effective visibility and the list stem is always considered private.
To check the effective visibility of an AST node, the AST node is mapped to a HIR node with `Resolver::local_def_id`, which returns the (private) list stem for nested use items.
</details>
For `extern crate`, there was a hack in rustdoc that stored the `DefId` of the crate itself in the cleaned item, instead of the `DefId` of the `extern crate` item. This made rustdoc look at the resolved links of the extern crate's crate root instead of the `extern crate` item. I've removed this hack and instead translate the `DefId` in the appropriate places.
As as side effect of fixing `extern crate`, i've turned
```rust
#[doc(masked)]
extern crate self as _;
```
into a no-op instead of hiding all trait impls. Proper verification for `doc(masked)` is included as a bonus.
fixes https://github.com/rust-lang/rust/issues/113896