惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 司徒正美
大猫的无限游戏
大猫的无限游戏
Scott Helme
Scott Helme
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
S
Secure Thoughts
Google DeepMind News
Google DeepMind News
博客园_首页
Hacker News: Ask HN
Hacker News: Ask HN
量子位
Jina AI
Jina AI
I
InfoQ
V
V2EX
Martin Fowler
Martin Fowler
Y
Y Combinator Blog
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
B
Blog
IT之家
IT之家
云风的 BLOG
云风的 BLOG
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - Franky
博客园 - 【当耐特】
N
Netflix TechBlog - Medium
Cloudbric
Cloudbric
H
Heimdal Security Blog
TaoSecurity Blog
TaoSecurity Blog
S
Security @ Cisco Blogs
U
Unit 42
Project Zero
Project Zero
Webroot Blog
Webroot Blog
The Register - Security
The Register - Security
N
News | PayPal Newsroom
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
Forbes - Security
Forbes - Security
宝玉的分享
宝玉的分享
Last Week in AI
Last Week in AI
C
Check Point Blog
博客园 - 聂微东
M
MIT News - Artificial intelligence
有赞技术团队
有赞技术团队
D
DataBreaches.Net
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
J
Java Code Geeks
G
Google Developers Blog
GbyAI
GbyAI
T
Threatpost

Rust Blog

Security Advisory for Cargo (CVE-2026-5223) | Rust Blog Security Advisory for Cargo (CVE-2026-5222) | Rust Blog Project goals update — April 2026 (end of 2025H2) | Rust Blog Rust is participating in Outreachy | Rust Blog Raising the baseline for the `nvptx64-nvidia-cuda` target | Rust Blog Announcing Google Summer of Code 2026 selected projects | Rust Blog Announcing Rust 1.95.0 | Rust Blog docs.rs: building fewer targets by default | Rust Blog Changes to WebAssembly targets and handling undefined symbols | Rust Blog Announcing Rust 1.94.1 | Rust Blog Security advisory for Cargo | Rust Blog What we heard about Rust's challenges | Rust Blog Call for Testing: Build Dir Layout v2 | Rust Blog Announcing rustup 1.29.0 | Rust Blog Announcing Rust 1.94.0 | Rust Blog 2025 State of Rust Survey Results | Rust Blog Rust debugging survey 2026 | Rust Blog Update on the October 15, 2018 incident on crates.io Announcing Rust 1.29.2 Announcing Rust 1.29 Announcing Rust 1.28 What is Rust 2018? Announcing Rust 1.27.2 Announcing Rust 1.27.1 Security Advisory for rustdoc Announcing Rust 1.27 Announcing Rust 1.26.2 Announcing Rust 1.26.1 Rust turns three Announcing Rust 1.26 The Rust Team All Hands in Berlin: a Recap Increasing Rust’s Reach 2018 Announcing Rust 1.25 Rust's 2018 roadmap Announcing Rust 1.24.1 Announcing Rust 1.24 The 2018 Rust Event Lineup Announcing Rust 1.23 New Year's Rust: A Call for Community Blogposts Rust in 2017: what we achieved Announcing Rust 1.22 (and 1.22.1) Fearless Concurrency in Firefox Quantum Announcing Rust 1.21 impl Future for Rust Rust 2017 Survey Results Announcing Rust 1.20 Announcing Rust 1.19 The 2017 Rust Conference Lineup Rust's 2017 roadmap, six months in Increasing Rust’s Reach Announcing Rust 1.18 Two years of Rust The Rust Libz Blitz Launching the 2017 State of Rust Survey Announcing Rust 1.17 Announcing Rust 1.16 Rust's language ergonomics initiative Announcing Rust 1.15.1 Rust's 2017 roadmap Announcing Rust 1.15 Announcing Rust 1.14 Announcing the First Underhanded Rust Contest Announcing Rust 1.13 Announcing Rust 1.12.1 Announcing Rust 1.12 Incremental Compilation Announcing Rust 1.11 Shape of errors to come The 2016 Rust Conference Lineup Announcing Rust 1.10 State of Rust Survey 2016 Announcing Rust 1.9 One year of Rust Taking Rust everywhere with rustup Launching the 2016 State of Rust Survey Cargo: predictable dependency management Introducing MIR Announcing Rust 1.8 Announcing Rust 1.7 Announcing Rust 1.6 Announcing Rust 1.5 Announcing Rust 1.4 Announcing Rust 1.3 Rust in 2016 Announcing Rust 1.2 Rust 1.1 stable, the Community Subteam, and RustCamp Announcing Rust 1.0 Abstraction without overhead: traits in Rust Rust Once, Run Everywhere Mixing matching, mutation, and moves in Rust Fearless Concurrency with Rust Announcing Rust 1.0 Beta Announcing Rust 1.0.0.alpha.2 Rust 1.0: status report and final timeline Announcing Rust 1.0 Alpha Rust 1.0: Scheduling the trains Yehuda Katz and Steve Klabnik are joining the Rust Core Team Cargo: Rust's community crate host Stability as a Deliverable Road to Rust 1.0
Intra-doc links close to stabilization | Inside Rust Blog
Manish Goregaokar and Jynn Nelson on behalf of the rustdoc · 2020-09-17 · via Rust Blog

We're excited to share that intra-doc links are stabilizing soon!

Intra-doc links are a feature of rustdoc that allow you to link to 'items' - functions, types, and more - by their name, instead of a hard-coded URL. This lets you have accurate links even if your types are re-exported in a different module or crate. Here is a simple example:

/// Link to [`f()`]
pub struct S;

pub fn f() {}

Intra-doc links have been around for a while, all the way back since 2017! They have been available on nightly without flags (and thus, on docs.rs), so you may be surprised to hear that they weren't yet stable. What's changing now is that they will be available on stable Rust, which also means we are more confident in the implementation and would strongly encourage their use. We recommend that you switch your libraries to use intra-doc links, which will fix broken links for re-exported types and links to different crates. We hope to add support for automating this process with cargo fix in the future.

I (Manish) and QuietMisdreavus started working on them in December 2017. Mozilla had given the whole company a couple weeks off after the release of Firefox Quantum, and I was visiting family in Mumbai. This meant that I had a fair amount of free time, and we were in diametrically opposite timezones. QuietMisdreavus had been working on the feature for a while but was less familiar with rustc's path resolution code, so I decided to help. We ended up pairing for those few weeks: during the day I'd write some code, discuss with QuietMisdreavus in the evening, and then hand it over for her to continue overnight. It was a great experience, pairing in open source can be really fun! This ended up in a 46-commit pull request with commits from both of us.

Unfortunately, we were not able to stabilize the feature at the time. The main blocker was cross-crate re-exports, things like the following:

// Crate `inner`
/// Link to [`f()`]
pub struct S;
pub fn f() {}
// outer crate
pub use inner::S;

The way rustdoc handles reexports is that it renders the reexport in-situ, parsing and rendering all of the markdown. The issue here is that rustdoc, when documenting outer, does not have access to the local scope information of inner::S and cannot resolve f().

These links were the original motivation for intra-doc links, so if we couldn't get them working, there wasn't much point in stabilizing! They also had the downside that they could silently break - the documentation would work when you built it, but any user of your API could re-export your types and cause the links to be broken.

At the time, persisting local scope information so that rustdoc invocations on downstream crates could access them would involve a significant amount of work on the compiler. It was work the compiler team wanted to be done anyway, but it was a lot, and neither of us had the bandwidth to do it, so we filed a bug and went on our way.

What changed?

Early in June, I (Jynn) got tired of not being able to use intra-doc links. I started investigating the issue to see if there was a fix. It was marked as E-hard, so I wasn't expecting miracles, but I thought I might at least make a start on it.

It turns out there was a simple problem with the implementation - it assumed all items were in the current crate! Clearly, that's not always the case. The fix turned out to be easy enough that I could implement it as my first contribution to rustdoc.

Note from Manish: Actually, the distinction between DefId and LocalDefId didn't exist when we wrote the feature, and the code would only resolve paths based on the resolver's current internal scope (which can only be within the current crate, since that is the only scope information the resolver had at the time). However, over time the compiler gained the ability to store and query resolution scopes of dependencies. We never noticed, and continued to believe that there was a large piece of work blocking stabilization.

However, my solution had one small problem: on certain carefully crafted inputs, it would crash:

#![feature(decl_macro)]
fn main() {
    || {
        macro m() {}
    };
}
thread 'rustc' panicked at 'called `Option::unwrap()` on a `None` value', /home/jyn/src/rust/src/librustc_hir/definitions.rs:358:9

HirIds and DefIds and trees, oh my!

(If you're not interested in the internals of the Rust compiler, feel free to skip this section.)

The error above came because of a pass called everybody_loops. A compiler 'pass' is a transformation on the source code, for example finding items without documentation. The everybody_loops pass turns the above code into:

fn main() {
    {
        macro m { () => { } }
    }
    loop  { }
}

As part of my changes for resolving cross-crate items, I needed to know the first parent module, so I could tell what items were in scope. Note however, that after everybody_loops the closure has disappeared! The crash happened because rustdoc was trying to access a closure that rustc didn't think existed (in compiler jargon, it was turning the DefId for the closure, which works across crates, into a HirId, which is specific to the current crate but contains a lot more info).

Why is this hard?

This turned out to be an enormous rabbit hole. everybody_loops was introduced all the way back in 2017 to solve another long-standing issue: rustdoc doesn't know how to deal with conditional compilation. What it lets rustdoc (and by extension, the standard library) do is ignore type and name errors in function bodies. This allows documenting both Linux and Windows APIs on the same host, even though the implementations would normally be broken. As seen above, the way it works is by turning every function body into loop {} - this is always valid, because loop {} has type !, which coerces to any type!

As we saw above, though, this transformation broke rustdoc. Additionally, it was causing lots of other problems.

So I got rid of it! This was Don't run everybody_loops. It is the single largest PR I've ever made to rustc, and hopefully the largest I will ever make. The issue was that the errors from libstd haven't gone away - if anything, it had been expanded since 2017. The hack I came up with was to, instead of running type checking and trying to rewrite the code into something that was valid, never run type checking in function bodies at all! This is both less work and closer to the semantics rustdoc wants. In particular, it never causes the invalid states that were crashing rustdoc.

Aftermath: No good deed goes unpunished

About a month after the PR was merged, rustdoc got a bug report: the docs for async-std failed to build on the nightly channel. Their code looked something like the following:

mod windows {
    pub trait WinFoo {
        fn foo(&self) {}
    }
    impl WinFoo for () {}
}

#[cfg(any(windows, doc))]
use windows::*;

mod unix {
    pub trait UnixFoo {
        fn foo(&self) {}
    }
    impl UnixFoo for () {}
}

#[cfg(any(unix, doc))]
use unix::*;

async fn bar() {
    ().foo()
}

In particular, notice that under cfg(doc), both traits would be in scope with the same method, so it would be ambiguous which to use for .foo(). This is exactly the sort of problem meant to be solved by not running type-checking. Unfortunately, since it was used in an async fn, type checking was still being run; bar desugars to a closure of the following form:

fn bar() -> impl Future<Output = ()> {
    async {
        ().foo()
    }
}

Because the function returned impl Future, that required type-checking the body to infer the return type of the function. That's exactly what rustdoc wanted not to do!

The hacky 'fix' implemented was to not infer the type of the function at all - rustdoc doesn't care about the exact type, only the traits that it implements. This was such a hack there's an issue open to fix it.

Now that cross-crate re-exports work, there isn't much standing in the way of stabilizing intra-doc links! There are a few cleanup PRs, but for the most part, the path to stabilization seems clear.

In the meantime, I've been working on various improvements to intra-doc links:

In particular, there have been a ton of people who stepped up to help convert the standard library to intra-doc links. A giant thank you to @camelid, @denisvasilik, @poliorcetics, @nixphix, @EllenNyan, @kolfs, @LeSeulArtichaut, @Amjad50, and @GuillaumeGomez for all their help!