Fix rustdoc handling of primitive items
This is a complicated PR and does a lot of things. I'm willing to split it up a little more if it would help reviewing, but it would be tricky and I'd rather not unless it's necessary.
## What does this do?
- Fixes https://github.com/rust-lang/rust/issues/73423.
- Fixes https://github.com/rust-lang/rust/issues/79630. I'm not sure how to test this for the standard library explicitly, but you can see from some of the diffs from the `no_std` tests. I also tested it locally and it works correctly: ![image](https://user-images.githubusercontent.com/23638587/125214383-e1fdd000-e284-11eb-8048-76b5df958aad.png)
- Fixes https://github.com/rust-lang/rust/issues/83083.
## Why are these changes interconnected?
- Allowing anchors (https://github.com/rust-lang/rust/issues/83083) without fixing the online/offline problem (https://github.com/rust-lang/rust/issues/79630) will actually just silently discard the anchors, that's not a fix. The online/offline problem is directly related to the fragment hack; links need to go through `fn href()` to be fixed.
- Technically I could fix the online/offline problem without removing the error on anchors; I am willing to separate that out if it would be helpful for reviewing. However I can't fix the anchor problem without adding docs to core, since rustdoc needs all those primitives to have docs to avoid a fallback, and currently `#![no_std]` crates don't have docs for primitives. I also can't fix the online/offline problem without removing the fragment hack, since otherwise diffs like this will be wrong for some primitives but not others:
```diff
`@@` -385,7 +381,7 `@@` fn resolve_primitive_associated_item(
ty::AssocKind::Const => "associatedconstant",
ty::AssocKind::Type => "associatedtype",
};
- let fragment = format!("{}#{}.{}", prim_ty.as_sym(), out, item_name);
+ let fragment = format!("{}.{}", out, item_name);
(Res::Primitive(prim_ty), fragment, Some((kind.as_def_kind(), item.def_id)))
})
})
```
- Adding primitive docs to core without making any other change will cause links to go to `core` instead of `std`, even for crates with `extern crate std`. See "Breaking changes to doc(primitive)" below for why this is the case. That said, I could add some special casing to rustdoc at the same time that would let me separate this change from the others (it would fix https://github.com/rust-lang/rust/issues/73423 but still special-case intra-doc links). I'm willing to separate that out if helpful for reviewing.
### Add primitive documentation to libcore
This works by reusing the same `include!("primitive_docs.rs")` file in both core and std, and then special-casing links in core to use relative links instead of intra-doc links. This doesn't use purely intra-doc links because some of the primitive docs links to items only in std; this doesn't use purely relative links because that introduces new broken links when the docs are re-exported (e.g. String's `&str` deref impl, or Vec's slice deref impl).
Note that this copies the whole file to core, to avoid anyone compiling core to have to set `CARGO_PKG_NAME`. See https://rust-lang.zulipchat.com/#narrow/stream/122651-general/topic/Who.20should.20review.20changes.20to.20linkchecker.3F/near/249939598 for more context. It also adds a tidy check to make sure the two files are kept in sync.
### Fix inconsistent online/offline primitive docs
This does four things:
- Records modules with `doc(primitive)` in `cache.external_paths`. This is necessary for `href()` to find them later.
- Makes `cache.primitive_locations` available to the intra-doc link pass, by refactoring out a `PrimitiveType::primitive_locations` function that only uses `TyCtxt`.
- Special cases modules with `doc(primitive)` to be treated as always public for the purpose of links.
- Removes the fragment hack. cc `@notriddle,` I know you added some comments about this in the code (thank you for that!)
### Breaking changes to `doc(primitive)`
"Breaking" is a little misleading here - these are changes in behavior, none of them will cause code to fail to compile.
Let me preface this by saying I think stabilizing `doc(primitive)` was a uniquely terrible idea. As far as I can tell, it was stabilized by oversight; it's been stable since 1.0. No one should have need to use it except the standard library, and a crater run shows that in fact no one is using it: https://github.com/rust-lang/rust/pull/87050#issuecomment-886166706. I hope to actually make `doc(primitive)` a no-op unless you opt-in with a nightly feature, which will keep crates compiling without forcing rustdoc into trying to keep somewhat arbitrary behavior guarantees; but for now, this just subtly changes some of the behavior if you use `doc(primitive)` in a dependency.
That said, here are the changes:
- Refactoring out `primitive_locations()` is technically a change in behavior, since it no longer looks for primitives in crates that were passed through `--extern`, but not used by the crate; however, that seems like such an unlikely edge case it's not worth dealing with.
- The precedence given to primitive locations is no longer just arbitrary, it can also be inconsistent from run to run. Let me explain that more: previously, primitive locations were sorted by the `CrateNum`; the comment on that sort said "Favor linking to as local extern as possible, so iterate all crates in reverse topological order." Unfortunately, that's not actually what CrateNum tracks: it measures the order crates are loaded, not the number of intermediate crates between that dependency and the root crate. It happened to work as intended before because the compiler injects `extern crate std;` at the top of every crate, which ensured it would have the first CrateNum other than the current, but every other CrateNum was completely arbitrary (for example, `core` often had a later CrateNum than `std`). This now removes the sort on CrateNum completely and special-cases core instead. In particular, if you depend on both `std` and a crate which defines a `doc(primitive)` module, it's arbitrary whether rustdoc will use the docs from std or the ones from the other crate. cc `@alexcrichton,` you wrote this originally.
cc `@rust-lang/rustdoc`
cc `@rust-lang/libs` for the addition to `core` (the commit you're interested in is 91346c8293)
Most of these are because alloc uses `#[lang_item]` to define methods,
but core documents primitives before those methods are available.
- Fix rustdoc-js-std test
For some reason this change made CStr not show up in the results for
`str,u8`. Since it still shows up for str, and since it wasn't a great
match for that query anyway, I think this is ok to let slide.
- Add test that all primitives can be linked to
- Enable `doc(primitive)` in `core` as well
- Add linkcheck exception specifically for Windows
Ideally this would be done automatically by the linkchecker by
replacing `\\` with forward slashes, but this PR is already a ton of
work ...
- Don't forcibly fail linkchecking if there's a broken intra-doc link on Windows
Previously, it would exit with a hard error if a missing file had `::`
in it. This changes it to report a missing file instead, which allows
adding an exception.
- Fix broken handling of primitive associated items
- Remove fragment hack
Fixes 83083
- more logging
- Update CrateNum hacks
The CrateNum has no relation to where in the dependency tree the crate
is, only when it's loaded. Explicitly special-case core instead of
assuming it will be the first DefId.
- Update and add tests
- Cache calculation of primitive locations
This could possibly be avoided by passing a Cache into
collect_intra_doc_links; but that's a much larger change, and doesn't
seem valuable other than for this.
This works by doing two things:
- Adding links that are specific to the crate. Since not all primitive
items are defined in `core` (due to lang_items), these need to use
relative links and not intra-doc links.
- Duplicating `primitive_docs` in both core and std. This allows not needing CARGO_PKG_NAME to build the standard library. It also adds a tidy check to make sure they stay the same.
Encode spans relative to the enclosing item
The aim of this PR is to avoid recomputing queries when code is moved without modification.
MCP at https://github.com/rust-lang/compiler-team/issues/443
This is achieved by :
1. storing the HIR owner LocalDefId information inside the span;
2. encoding and decoding spans relative to the enclosing item in the incremental on-disk cache;
3. marking a dependency to the `source_span(LocalDefId)` query when we translate a span from the short (`Span`) representation to its explicit (`SpanData`) representation.
Since all client code uses `Span`, step 3 ensures that all manipulations
of span byte positions actually create the dependency edge between
the caller and the `source_span(LocalDefId)`.
This query return the actual absolute span of the parent item.
As a consequence, any source code motion that changes the absolute byte position of a node will either:
- modify the distance to the parent's beginning, so change the relative span's hash;
- dirty `source_span`, and trigger the incremental recomputation of all code that
depends on the span's absolute byte position.
With this scheme, I believe the dependency tracking to be accurate.
For the moment, the spans are marked during lowering.
I'd rather do this during def-collection,
but the AST MutVisitor is not practical enough just yet.
The only difference is that we attach macro-expanded spans
to their expansion point instead of the macro itself.
Refactor query forcing
The control flow in those functions was very complex, with several layers of continuations.
I tried to simplify the implementation, while keeping essentially the same logic.
Now, all code paths go through `try_execute_query` for the actual query execution.
Communication with the `dep_graph` and the live caches are the only difference between query getting/ensuring/forcing.
Rollup of 10 pull requests
Successful merges:
- #87904 (Reword description of automatic impls of `Unsize`.)
- #88147 (Fix non-capturing closure return type coercion)
- #88209 (Improve error message when _ is used for in/inout asm operands)
- #88668 (Change more x64 size checks to not apply to x32.)
- #88733 (Fix ICE for functions with more than 65535 arguments)
- #88757 (Suggest wapping expr in parentheses on invalid unary negation)
- #88779 (Use more accurate spans for "unused delimiter" lint)
- #88830 (Add help for E0463)
- #88849 (don't clone types that are Copy (clippy::clone_on_copy))
- #88850 (don't convert types into identical types)
Failed merges:
r? `@ghost`
`@rustbot` modify labels: rollup
Fix ICE for functions with more than 65535 arguments
This pull request fixes#88577 by changing the `param_idx` field in the `Param` variant of `WellFormedLoc` from `u16` to `u32`, thus allowing for more than 65,535 arguments in a function. Note that I also added a regression test, but needed to add `// ignore-tidy-filelength` because the test is more than 8000 lines long.
Change more x64 size checks to not apply to x32.
Commit 95e096d6 changed a bunch of size checks already, but more have
been added, so this fixes the new ones the same way: the various size
checks that are conditional on target_arch = "x86_64" were not intended
to apply to x86_64-unknown-linux-gnux32, so add
target_pointer_width = "64" to the conditions.
Fix non-capturing closure return type coercion
Fixes#88097. For the example given there:
```rust
fn peculiar() -> impl Fn(u8) -> u8 {
return |x| x + 1
}
```
which incorrectly reports an error, I noticed something weird in the debug log:
```
DEBUG rustc_typeck::check::coercion coercion::try_find_coercion_lub([closure@test.rs:2:12: 2:21], [closure@test.rs:2:12: 2:21], exprs=1 exprs)
```
Apparently, `try_find_coercion_lub()` thinks that the LUB for two closure types always has to be a function pointer (which explains the `expected closure, found fn pointer` error in #88097). There is one corner case where that isn't true, though — namely, when the two closure types are equal, in which case the trivial LUB is the type itself. This PR fixes this by inserting an explicit check for type equality in `try_find_coercion_lub()`.
Reword description of automatic impls of `Unsize`.
The existing documentation felt a little unhelpfully concise, so this change tries to improve it by using longer sentences, each of which specifies which kinds of types it applies to as early as possible. In particular, the third item starts with “Structs ...” instead of saying “Foo is a struct” later.
Also, the previous list items “Only the last field has a type involving `T`” and “`T` is not part of the type of any other fields” are, as far as I see, redundant with each other, so I removed the latter.
I have no particular knowledge of `Unsize`; I have attempted to leave the meaning entirely unchanged but may have missed a nuance.
Markdown preview of the edited documentation:
> All implementations of `Unsize` are provided automatically by the compiler.
> Those implementations are:
>
> - Arrays `[T; N]` implement `Unsize<[T]>`.
> - Types implementing a trait `Trait` also implement `Unsize<dyn Trait>`.
> - Structs `Foo<..., T, ...>` implement `Unsize<Foo<..., U, ...>>` if all of these conditions
> are met:
> - `T: Unsize<U>`.
> - Only the last field of `Foo` has a type involving `T`.
> - `Bar<T>: Unsize<Bar<U>>`, where `Bar<T>` stands for the actual type of that last field.
rustc: use more correct span data in for loop desugaring
Fixes#82462
Before:
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
LL | for x in DroppingSlice(&*v).iter(); {
| +
After:
help: consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped
|
LL | };
| +
This seems like a reasonable fix: since the desugared "expr_drop_temps_mut" contains the entire desugared loop construct, its span should contain the entire loop construct as well.
Now that we encode spans relative to the items, the item's own span is
never actually hashed as part of the HIR.
In consequence, we explicitly include it in the crate hash to avoid
missing cross-crate invalidations.
Fix table in docblocks
"Overwrite" of #88702.
Instead of adding a z-index to the sidebar (which only hides the issue, doesn't fix it), I wrap `<table>` elements inside a `<div>` and limit all chidren of `.docblock` elements' width to prevent having the scrollbar on the whole doc block.
![Screenshot from 2021-09-08 15-11-24](https://user-images.githubusercontent.com/3050060/132515740-71796515-e74f-429f-ba98-2596bdbf781c.png)
Thanks `@nbdd0121` for `overflow-x: auto;`. ;)
r? `@notriddle`
RustWrapper: avoid deleted unclear attribute methods
These were deleted in https://reviews.llvm.org/D108614, and in C++ I
definitely see the argument for their removal. I didn't try and
propagate the changes up into higher layers of rustc in this change
because my initial goal was to get rustc working against LLVM HEAD
promptly, but I'm happy to follow up with some refactoring to make the
API on the Rust side match the LLVM API more directly (though the way
the enum works in Rust makes the API less scary IMO).
r? ``@nagisa`` cc ``@nikic``
Rustdoc coverage fields count
Follow-up of #88688.
Instead of requiring enum tuple variant fields and tuple struct fields to be documented, we count them if they are documented, otherwise we don't include them in the count.
r? `@Manishearth`