Skip to content

Conversation

@fmease
Copy link
Member

@fmease fmease commented Oct 27, 2025

How did #147981 happen?

  1. We don't parse intra-doc links as Rust paths or qpaths. Instead they follow a very lenient bespoke grammar. We completely ignore Markdown links if they contain characters that don't match /[a-zA-Z0-9_:<>, !*&;]/ (we don't even emit lint broken-intra-doc-links for these).
  2. PR #132748 made rustdoc intepret more Markdown links as potential intra-doc links. Namely, if the link is surrounded by backticks (and some other conditions apply) then it doesn't matter if the (partially processed) link contains bad characters as defined above (cc ignore_urllike && should_ignore_link(path_str)).
  3. However, rustdoc's preprocess_link must be kept in sync with a simplified counterpart in rustc. More specifically, whenever rustdoc's preprocessor returns a successful result then rustc's must yield the same result. Otherwise, rustc doesn't resolve the necessary links for rustdoc.
  4. This uncovered a "dormant bug" / "mistake" in rustc's preprocess_link. Namely, when presented with a link like struct@Type@suffix, it didn't cut off the disambiguator if present (here: struct@). Instead it rsplit('@') which is incorrect if the "path" contains @ itself (yielding suffix instead of Type@suffix here). Prior to PR #132748, a link like [`struct@Type@suffix`] was not considered a potential intra-doc link / worth querying rustc for. Now it is due to the backticks.
  5. Finally, since rustc didn't record a resolution for Type@suffix (it only recorded suffix (to be Res::Err)), we triggered an assertion we have in place to catch cases like this.

Fixes #147981.

I didn't and still don't have the time to investigate if #132748 led to more rustc/rustdoc mismatches (after all, the PR makde rustdoc's preprocess_link return Some(Ok(_)) in more cases). I've at least added another much needed "warning banner" & made the existing one more flashy.

While this fixes a stable-to-beta regression, I don't think it's worth beta backporting, esp. since it's only P-medium and since the final 1.91 release steps commence today / the next days, so it would only be stressful to get it in on time. However, feel free to nominate.

r? @lolbinarycat

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue. labels Oct 27, 2025
Comment on lines +949 to +951
// IMPORTANT: To be kept in sync with the corresponding function in `rustc_resolve::rustdoc`.
// Namely, whenever this function successfully returns a `path_str` for a given input, the
// rustc counterpart *MUST* return the same result!
Copy link
Member Author

@fmease fmease Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such a warning banner is clearly needed. They do get out of sync from time to time. Another older example: Issue #110495 / PR #110501.

Copy link
Contributor

@lolbinarycat lolbinarycat left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like a simple fix, just a few nitpicks and questions

View changes since this review

// certain link kinds cannot have their path be urls,
// so they should not be ignored, no matter how much they look like urls.
// e.g. [https://example.com/] is not a link to example.com.
// e.g. `[https://example.com/]` is not a link to example.com.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is confusing to use markdown syntax in a remark about markdown syntax, as `[https://example.com/]` and [https://example.com/] are different things, and we are talking about the latter, not the former.

Maybe we can just use " quotes?

);

// [] is mostly likely not supposed to be a link
// `[]` is mostly likely not supposed to be a link
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A bit less confusing than above, but I still am kinda meh on the idea of non-doc comments always using markdown syntax. Maybe there's a valid reason for it I'm unaware of but idk.

Comment on lines 395 to +399
/// Simplified version of the corresponding function in rustdoc.
/// If the rustdoc version returns a successful result, this function must return the same result.
/// Otherwise this function may return anything.
fn preprocess_link(link: &str) -> Box<str> {
// IMPORTANT: To be kept in sync with the corresponding function in rustdoc.
// Namely, whenever the rustdoc function returns a successful result for a
// given input, this function *MUST* return the same result!
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Somewhere in here we should mention that path_str is the field of PreprocessingInfo this return value corresponds to.

let link = link.split('#').next().unwrap();
let link = link.trim();
let link = link.rsplit('@').next().unwrap();
let link = link.split_once('@').map_or(link, |(_, link)| link);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
let link = link.split_once('@').map_or(link, |(_, link)| link);
let link = link.split_once('@').map_or(link, |(_, x)| x);

nit: 3 different variables named link all being referenced on the same line might be a bit much.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I probably won't name it x since I'm not a fan of non-descriptive identifiers but I'll probably name it right or suffix.

Comment on lines -408 to +411
strip_generics_from_path(link).unwrap_or_else(|_| link.into())
let link = strip_generics_from_path(link).unwrap_or_else(|_| link.into());
link
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just curious: why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leftover from printf dbg'ing, will revert

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-rustdoc Relevant to the rustdoc team, which will review and decide on the PR/issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

regression: ICE no resolution for ...

3 participants