Change:
Crate exports from . is documented in quit and has no documentation in quitmacros. When that documentation has a link to , which is only in crate quit, it is unresolved. However, is resolved. Rustdoc gives no warnings with either. You can see the result with quit version 1.1.1 . cc cc
<details<summaryAll of this was wrong, I forgot to use +nightly</summaryThis isn't related to scopes, rustdoc will also fail to resolve these links: Something about the re-export itself is messing it up. </details
The good news is this is unrelated to proc-macros. Here's what I found: This is really strange. I would have expected it to resolve relative to , not relative to the current crate.
Ok, I found the issue: rustdoc and resolve disagree about which crate this is in For , rustdoc passes the original module of String, , and resolve correctly says there's no item named . But for , resolve thinks that refers to the current crate, not to alloc. This explains a lot of other broken links I've been seeing actually: anything that has will be wrong. So you were actually correct to start that this was the same issue as ;) The fix will be a little tricky ... there's no 'change ' button for resolve. There are a few things rustdoc can do: all links relative to the current module (the status quo before ). This is a no-go, because it means links will break on re-exports (). all links relative to the original module. This is what I thought was the current behavior. It means that additional documentation can't refer to things in the current lexical scope, which is non-intuitive (cc ). links in lexical scope: the original docs get resolved in the original module; the new docs get resolved in the module with the re-export. This is the ideal fix but somewhat hard to do because rustdoc doesn't distinguish between the two internally. A possible way to implement 2. is by stripping wherever we see it and resolving relative to the crate root instead of the current module. This is slightly_ hacky but should work fairly reliably.
Marking as P-high after discussing with ; it would be unfortunate to still have this bug on the first release after stabilization.

Discussion:
/// types that can be `==` without being identical. See the [module-level /// documentation] for more. /// <del> /// [module-level documentation]: crate::collections#insert-and-complex-keys </del> <ins> /// [module-level documentation]: index.html#insert-and-complex-keys </ins> /// /// # Examples ///

parent_node }; <del> let module_id = if let Some(id) = base_node { </del> <ins> let mut module_id = if let Some(id) = base_node { </ins> id } else { debug!("attempting to resolve item without parent module: {}", path_str);

resolved_self = format!("{}::{}", name, &path_str[6..]); path_str = &resolved_self; } <ins> } else if path_str.starts_with("crate::") { use rustc_span::def_id::CRATE_DEF_INDEX; // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented. // But rustdoc wants it to mean the crate this item was originally present in. // To work around this, remove it and resolve relative to the crate root instead. // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root. resolved_self = format!("self::{}", &path_str["crate::".len()..]); path_str = &resolved_self; module_id = DefId { krate: item.def_id.krate, index: CRATE_DEF_INDEX }; </ins> } match self.resolve_with_disambiguator(

<ins> #![crate_name = "inner"] /// Links to [crate::g] pub fn f() {} pub fn g() {} </ins>

<ins> // aux-build:intra-link-cross-crate-crate.rs // build-aux-docs #![crate_name = "outer"] extern crate inner; // @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g" pub use inner::f; </ins>