Skip to content

Commit 7b46920

Browse files
committed
Fix linkcheck issues
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.
1 parent cb7e527 commit 7b46920

File tree

6 files changed

+45
-8
lines changed

6 files changed

+45
-8
lines changed

library/core/src/char/methods.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ impl char {
2424
/// decoding error.
2525
///
2626
/// It can occur, for example, when giving ill-formed UTF-8 bytes to
27-
/// [`String::from_utf8_lossy`](string/struct.String.html#method.from_utf8_lossy).
27+
/// [`String::from_utf8_lossy`](../std/string/struct.String.html#method.from_utf8_lossy).
2828
#[stable(feature = "assoc_char_consts", since = "1.52.0")]
2929
pub const REPLACEMENT_CHARACTER: char = '\u{FFFD}';
3030

library/core/src/slice/mod.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -2257,9 +2257,9 @@ impl<T> [T] {
22572257
/// assert!(match r { Ok(1..=4) => true, _ => false, });
22582258
/// ```
22592259
// Lint rustdoc::broken_intra_doc_links is allowed as `slice::sort_by_key` is
2260-
// in crate `alloc`, and as such doesn't exists yet when building `core`.
2261-
// links to downstream crate: #74481. Since primitives are only documented in
2262-
// libstd (#73423), this never leads to broken links in practice.
2260+
// in crate `alloc`, and as such doesn't exists yet when building `core`: #74481.
2261+
// This breaks links when slice is displayed in core, but changing it to use relative links
2262+
// would break when the item is re-exported. So allow the core links to be broken for now.
22632263
#[allow(rustdoc::broken_intra_doc_links)]
22642264
#[stable(feature = "slice_binary_search_by_key", since = "1.10.0")]
22652265
#[inline]

src/librustdoc/clean/types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1774,7 +1774,7 @@ impl PrimitiveType {
17741774
debug!(?crate_num, ?crate_name);
17751775
for &(def_id, prim) in &e.primitives(tcx) {
17761776
// HACK: try to link to std instead where possible
1777-
if crate_name == sym::core && primitive_locations.get(&prim).is_some() {
1777+
if crate_name == sym::core && primitive_locations.contains_key(&prim) {
17781778
continue;
17791779
}
17801780
primitive_locations.insert(prim, def_id);

src/test/rustdoc-js-std/multi-query.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ const QUERY = 'str,u8';
22

33
const EXPECTED = {
44
'others': [
5-
{ 'path': 'std', 'name': 'str' },
6-
{ 'path': 'std', 'name': 'u8' },
7-
{ 'path': 'std::ffi', 'name': 'CStr' },
5+
{ 'path': 'std', 'name': 'str', 'href': '../std/primitive.str.html' },
6+
{ 'path': 'std', 'name': 'u8', 'href': '../std/primitive.u8.html' },
7+
{ 'path': 'std', 'name': 'str', 'href': '../std/str/index.html' },
8+
{ 'path': 'std', 'name': 'u8', 'href': '../std/u8/index.html' },
89
],
910
};

src/test/rustdoc/primitive/no_std.rs

+10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
#![no_std]
2+
#![deny(warnings)]
3+
#![deny(rustdoc::broken_intra_doc_links)]
24

35
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'u8'
46
// @has no_std/fn.foo.html '//a/[@href="{{channel}}/core/primitive.u8.html"]' 'primitive link'
57
/// Link to [primitive link][u8]
68
pub fn foo() -> u8 {}
9+
10+
// Test that all primitives can be linked to.
11+
/// [isize] [i8] [i16] [i32] [i64] [i128]
12+
/// [usize] [u8] [u16] [u32] [u64] [u128]
13+
/// [f32] [f64]
14+
/// [char] [bool] [str] [slice] [array] [tuple] [unit]
15+
/// [pointer] [reference] [fn] [never]
16+
pub fn bar() {}

src/tools/linkchecker/main.rs

+26
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,27 @@ use regex::Regex;
3030
// If at all possible you should use intra-doc links to avoid linkcheck issues. These
3131
// are cases where that does not work
3232
// [(generated_documentation_page, &[broken_links])]
33+
#[rustfmt::skip]
3334
const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[
3435
// These try to link to std::collections, but are defined in alloc
3536
// https://github.com/rust-lang/rust/issues/74481
3637
("std/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
3738
("std/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
3839
("alloc/collections/btree_map/struct.BTreeMap.html", &["#insert-and-complex-keys"]),
3940
("alloc/collections/btree_set/struct.BTreeSet.html", &["#insert-and-complex-keys"]),
41+
42+
// These try to link to various things in std, but are defined in core.
43+
// The docs in std::primitive use proper intra-doc links, so these seem fine to special-case.
44+
// Most these are broken because liballoc uses `#[lang_item]` magic to define things on
45+
// primitives that aren't available in core.
46+
("alloc/slice/trait.Join.html", &["#method.join"]),
47+
("alloc/slice/trait.Concat.html", &["#method.concat"]),
48+
("alloc/slice/index.html", &["#method.concat", "#method.join"]),
49+
("alloc/vec/struct.Vec.html", &["#method.sort_by_key", "#method.sort_by_cached_key"]),
50+
("core/primitive.str.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase"]),
51+
("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase",
52+
"core/slice::sort_by_key", "core\\slice::sort_by_key",
53+
"#method.sort_by_cached_key"]),
4054
];
4155

4256
#[rustfmt::skip]
@@ -376,6 +390,10 @@ impl Checker {
376390

377391
/// Load a file from disk, or from the cache if available.
378392
fn load_file(&mut self, file: &Path, report: &mut Report) -> (String, &FileEntry) {
393+
// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-
394+
#[cfg(windows)]
395+
const ERROR_INVALID_NAME: i32 = 123;
396+
379397
let pretty_path =
380398
file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string();
381399

@@ -392,6 +410,14 @@ impl Checker {
392410
}
393411
Err(e) if e.kind() == ErrorKind::NotFound => FileEntry::Missing,
394412
Err(e) => {
413+
// If a broken intra-doc link contains `::`, on windows, it will cause `ERROR_INVALID_NAME` rather than `NotFound`.
414+
// Explicitly check for that so that the broken link can be allowed in `LINKCHECK_EXCEPTIONS`.
415+
#[cfg(windows)]
416+
if e.raw_os_error() == Some(ERROR_INVALID_NAME)
417+
&& file.as_os_str().to_str().map_or(false, |s| s.contains("::"))
418+
{
419+
return FileEntry::Missing;
420+
}
395421
panic!("unexpected read error for {}: {}", file.display(), e);
396422
}
397423
});

0 commit comments

Comments
 (0)