Skip to content

Commit 03d6406

Browse files
committed
Auto merge of #162808 - GuillaumeGomez:std-link-to-def, r=<try>
Enable `--generate-link-to-definition` rustdoc option on std docs try-job: test-aarch64-msvc-2 try-job: test-x86_64-msvc-1
2 parents 16d1ffa + 6623b95 commit 03d6406

41 files changed

Lines changed: 495 additions & 20 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎compiler/rustc_builtin_macros/src/lib.rs‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ mod iter;
4646
mod log_syntax;
4747
mod offload;
4848
mod pattern_type;
49+
mod rustdoc_skip_body;
4950
mod source_util;
5051
mod test;
5152
mod test_binder_constraints;
@@ -125,6 +126,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
125126
eii_shared_macro: eii::eii_shared_macro,
126127
global_allocator: global_allocator::expand,
127128
offload_kernel: offload::expand_kernel,
129+
rustdoc_skip_body: rustdoc_skip_body::expand,
128130
test: test::expand_test,
129131
test_case: test::expand_test_case,
130132
unsafe_eii: eii::unsafe_eii,
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
//! The expansion from a function when the code would not compile with rustdoc: so if `cfg(doc)`,
2+
//! expands to a `loop {}`.
3+
4+
use rustc_ast::token::{self, Delimiter, IdentKind};
5+
use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
6+
use rustc_ast::{
7+
AssocItemKind, AttrArgs, AttrItem, Attribute, DelimArgs, ExprKind, Fn, ItemKind, MetaItem,
8+
Safety,
9+
};
10+
use rustc_expand::base::*;
11+
use rustc_span::{Ident, Span, sym};
12+
use thin_vec::ThinVec;
13+
14+
pub(crate) fn expand(
15+
cx: &mut ExtCtxt<'_>,
16+
attr_path_sp: Span,
17+
meta_item: &MetaItem,
18+
mut item: Annotatable,
19+
) -> Vec<Annotatable> {
20+
if !meta_item.is_word() {
21+
cx.dcx().struct_span_err(attr_path_sp, "`rustdoc_skip_body` doesn't take arguments").emit();
22+
}
23+
let mut is_expected_item = false;
24+
match item {
25+
Annotatable::Item(ref mut item) => {
26+
if let ItemKind::Fn(ref mut fn_) = item.kind {
27+
expand_macro(cx, attr_path_sp, fn_);
28+
is_expected_item = true;
29+
}
30+
}
31+
Annotatable::AssocItem(ref mut item, _) => {
32+
if let AssocItemKind::Fn(ref mut fn_) = item.kind {
33+
expand_macro(cx, attr_path_sp, fn_);
34+
is_expected_item = true;
35+
}
36+
}
37+
_ => {}
38+
}
39+
if !is_expected_item {
40+
cx.dcx()
41+
.struct_span_err(attr_path_sp, "`rustdoc_skip_body` can only be used on functions")
42+
.emit();
43+
}
44+
vec![item]
45+
}
46+
47+
fn cfg_not_doc(cx: &mut ExtCtxt<'_>, sp: Span) -> Attribute {
48+
// `not(doc)`
49+
let not_doc = TokenStream::new(vec![
50+
TokenTree::token_alone(token::Ident(sym::not, IdentKind::Normal), sp),
51+
TokenTree::Delimited(
52+
DelimSpan::from_single(sp),
53+
DelimSpacing::new(Spacing::JointHidden, Spacing::Alone),
54+
Delimiter::Parenthesis,
55+
TokenStream::token_alone(token::Ident(sym::doc, IdentKind::Normal), sp),
56+
),
57+
]);
58+
59+
cx.attr_nested(
60+
AttrItem {
61+
unsafety: Safety::Default,
62+
path: cx.path_ident(sp, Ident::new(sym::cfg, sp)),
63+
args: AttrArgs::Delimited(DelimArgs {
64+
dspan: DelimSpan::from_single(sp),
65+
delim: Delimiter::Parenthesis,
66+
tokens: not_doc,
67+
}),
68+
span: sp,
69+
},
70+
sp,
71+
)
72+
}
73+
74+
fn expand_macro(cx: &mut ExtCtxt<'_>, sp: Span, fn_: &mut Fn) {
75+
let Some(old_body) = fn_.body.take() else {
76+
// No body... Well, no possibility to not compile I guess so all good.
77+
return;
78+
};
79+
let mut old_body = cx.expr_block(old_body);
80+
// We add on the function's body `#[cfg(not(doc))]`.
81+
old_body.attrs.push(cfg_not_doc(cx, sp));
82+
83+
// We create the `#[cfg(doc)] loop {}` "block".
84+
let mut loop_expr = cx.expr(sp, ExprKind::Loop(cx.block(sp, ThinVec::new()), None, sp));
85+
loop_expr.attrs.push(cx.attr_nested_word(sym::cfg, sym::doc, sp));
86+
87+
let mut stmts = ThinVec::new();
88+
stmts.push(cx.stmt_expr(loop_expr));
89+
stmts.push(cx.stmt_expr(old_body));
90+
91+
// We create a new function body containing both blocks.
92+
fn_.body = Some(cx.block(sp, stmts));
93+
}

‎compiler/rustc_span/src/symbol.rs‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1912,6 +1912,7 @@ symbols! {
19121912
rustdoc,
19131913
rustdoc_internals,
19141914
rustdoc_missing_doc_code_examples,
1915+
rustdoc_skip_body,
19151916
rustfmt,
19161917
rvalue_static_promotion,
19171918
rvector,

‎library/std/src/macros.rs‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -461,3 +461,17 @@ macro_rules! hash_map {
461461
map
462462
}}
463463
}
464+
465+
/// Attribute macro to replace a function's body with `loop {}` under rustdoc.
466+
///
467+
/// This allows target-specific functions to be documented on other targets,
468+
/// even when their bodies reference items unavailable on the target used to
469+
/// build the documentation. Use this with `#[cfg(any(doc, ...))]` to include
470+
/// such functions in documentation builds.
471+
///
472+
/// The function's signature must still be valid on the documentation target.
473+
#[rustc_builtin_macro]
474+
#[allow(unused_macros)]
475+
pub(crate) macro rustdoc_skip_body($item:item) {
476+
/* compiler built-in */
477+
}

‎library/std/src/os/darwin/fs.rs‎

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
#![stable(feature = "metadata_ext", since = "1.1.0")]
55

66
use crate::fs::{self, Metadata};
7+
use crate::macros::rustdoc_skip_body;
78
use crate::sys::{AsInner, AsInnerMut, IntoInner};
89
use crate::time::SystemTime;
910

@@ -88,69 +89,91 @@ pub trait MetadataExt {
8889
impl MetadataExt for Metadata {
8990
#[allow(deprecated)]
9091
#[cfg(any(doc, target_os = "macos", target_os = "ios"))]
92+
#[rustdoc_skip_body]
9193
fn as_raw_stat(&self) -> &super::raw::stat {
9294
unsafe { &*(self.as_inner().as_inner() as *const libc::stat as *const super::raw::stat) }
9395
}
96+
#[rustdoc_skip_body]
9497
fn st_dev(&self) -> u64 {
9598
self.as_inner().as_inner().st_dev as u64
9699
}
100+
#[rustdoc_skip_body]
97101
fn st_ino(&self) -> u64 {
98102
self.as_inner().as_inner().st_ino as u64
99103
}
104+
#[rustdoc_skip_body]
100105
fn st_mode(&self) -> u32 {
101106
self.as_inner().as_inner().st_mode as u32
102107
}
108+
#[rustdoc_skip_body]
103109
fn st_nlink(&self) -> u64 {
104110
self.as_inner().as_inner().st_nlink as u64
105111
}
112+
#[rustdoc_skip_body]
106113
fn st_uid(&self) -> u32 {
107114
self.as_inner().as_inner().st_uid as u32
108115
}
116+
#[rustdoc_skip_body]
109117
fn st_gid(&self) -> u32 {
110118
self.as_inner().as_inner().st_gid as u32
111119
}
120+
#[rustdoc_skip_body]
112121
fn st_rdev(&self) -> u64 {
113122
self.as_inner().as_inner().st_rdev as u64
114123
}
124+
#[rustdoc_skip_body]
115125
fn st_size(&self) -> u64 {
116126
self.as_inner().as_inner().st_size as u64
117127
}
128+
#[rustdoc_skip_body]
118129
fn st_atime(&self) -> i64 {
119130
self.as_inner().as_inner().st_atime as i64
120131
}
132+
#[rustdoc_skip_body]
121133
fn st_atime_nsec(&self) -> i64 {
122134
self.as_inner().as_inner().st_atime_nsec as i64
123135
}
136+
#[rustdoc_skip_body]
124137
fn st_mtime(&self) -> i64 {
125138
self.as_inner().as_inner().st_mtime as i64
126139
}
140+
#[rustdoc_skip_body]
127141
fn st_mtime_nsec(&self) -> i64 {
128142
self.as_inner().as_inner().st_mtime_nsec as i64
129143
}
144+
#[rustdoc_skip_body]
130145
fn st_ctime(&self) -> i64 {
131146
self.as_inner().as_inner().st_ctime as i64
132147
}
148+
#[rustdoc_skip_body]
133149
fn st_ctime_nsec(&self) -> i64 {
134150
self.as_inner().as_inner().st_ctime_nsec as i64
135151
}
152+
#[rustdoc_skip_body]
136153
fn st_birthtime(&self) -> i64 {
137154
self.as_inner().as_inner().st_birthtime as i64
138155
}
156+
#[rustdoc_skip_body]
139157
fn st_birthtime_nsec(&self) -> i64 {
140158
self.as_inner().as_inner().st_birthtime_nsec as i64
141159
}
160+
#[rustdoc_skip_body]
142161
fn st_blksize(&self) -> u64 {
143162
self.as_inner().as_inner().st_blksize as u64
144163
}
164+
#[rustdoc_skip_body]
145165
fn st_blocks(&self) -> u64 {
146166
self.as_inner().as_inner().st_blocks as u64
147167
}
168+
#[rustdoc_skip_body]
148169
fn st_gen(&self) -> u32 {
149170
self.as_inner().as_inner().st_gen as u32
150171
}
172+
#[rustdoc_skip_body]
151173
fn st_flags(&self) -> u32 {
152174
self.as_inner().as_inner().st_flags as u32
153175
}
176+
#[rustdoc_skip_body]
154177
fn st_lspare(&self) -> u32 {
155178
self.as_inner().as_inner().st_lspare as u32
156179
}
@@ -171,6 +194,7 @@ pub impl(self) trait FileTimesExt {
171194

172195
#[stable(feature = "file_set_times", since = "1.75.0")]
173196
impl FileTimesExt for fs::FileTimes {
197+
#[rustdoc_skip_body]
174198
fn set_created(mut self, t: SystemTime) -> Self {
175199
self.as_inner_mut().set_created(t.into_inner());
176200
self

‎library/std/src/os/fd/owned.rs‎

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use super::raw::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
1010
use crate::alloc::Allocator;
1111
#[cfg(not(target_os = "trusty"))]
1212
use crate::fs;
13+
use crate::macros::rustdoc_skip_body;
1314
use crate::marker::PhantomData;
1415
use crate::mem::ManuallyDrop;
1516
#[cfg(not(any(
@@ -136,6 +137,7 @@ impl BorrowedFd<'_> {
136137
target_os = "motor"
137138
)))]
138139
#[stable(feature = "io_safety", since = "1.63.0")]
140+
#[rustdoc_skip_body]
139141
pub fn try_clone_to_owned(&self) -> io::Result<OwnedFd> {
140142
// We want to atomically duplicate this file descriptor and set the
141143
// CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
@@ -225,6 +227,7 @@ impl FromRawFd for OwnedFd {
225227
#[stable(feature = "io_safety", since = "1.63.0")]
226228
impl Drop for OwnedFd {
227229
#[inline]
230+
#[rustdoc_skip_body]
228231
fn drop(&mut self) {
229232
unsafe {
230233
// Note that errors are ignored when closing a file descriptor. According to POSIX 2024,
@@ -344,6 +347,7 @@ impl AsFd for OwnedFd {
344347
#[cfg(not(target_os = "trusty"))]
345348
impl AsFd for fs::File {
346349
#[inline]
350+
#[rustdoc_skip_body]
347351
fn as_fd(&self) -> BorrowedFd<'_> {
348352
self.as_inner().as_fd()
349353
}
@@ -354,6 +358,7 @@ impl AsFd for fs::File {
354358
impl From<fs::File> for OwnedFd {
355359
/// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
356360
#[inline]
361+
#[rustdoc_skip_body]
357362
fn from(file: fs::File) -> OwnedFd {
358363
file.into_inner().into_inner().into_inner()
359364
}
@@ -365,6 +370,7 @@ impl From<OwnedFd> for fs::File {
365370
/// Returns a [`File`](fs::File) that takes ownership of the given
366371
/// file descriptor.
367372
#[inline]
373+
#[rustdoc_skip_body]
368374
fn from(owned_fd: OwnedFd) -> Self {
369375
Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
370376
}
@@ -374,6 +380,7 @@ impl From<OwnedFd> for fs::File {
374380
#[cfg(not(target_os = "trusty"))]
375381
impl AsFd for crate::net::TcpStream {
376382
#[inline]
383+
#[rustdoc_skip_body]
377384
fn as_fd(&self) -> BorrowedFd<'_> {
378385
self.as_inner().socket().as_fd()
379386
}
@@ -384,6 +391,7 @@ impl AsFd for crate::net::TcpStream {
384391
impl From<crate::net::TcpStream> for OwnedFd {
385392
/// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
386393
#[inline]
394+
#[rustdoc_skip_body]
387395
fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
388396
tcp_stream.into_inner().into_socket().into_inner().into_inner()
389397
}
@@ -393,6 +401,7 @@ impl From<crate::net::TcpStream> for OwnedFd {
393401
#[cfg(not(target_os = "trusty"))]
394402
impl From<OwnedFd> for crate::net::TcpStream {
395403
#[inline]
404+
#[rustdoc_skip_body]
396405
fn from(owned_fd: OwnedFd) -> Self {
397406
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
398407
owned_fd,
@@ -404,6 +413,7 @@ impl From<OwnedFd> for crate::net::TcpStream {
404413
#[cfg(not(target_os = "trusty"))]
405414
impl AsFd for crate::net::TcpListener {
406415
#[inline]
416+
#[rustdoc_skip_body]
407417
fn as_fd(&self) -> BorrowedFd<'_> {
408418
self.as_inner().socket().as_fd()
409419
}
@@ -414,6 +424,7 @@ impl AsFd for crate::net::TcpListener {
414424
impl From<crate::net::TcpListener> for OwnedFd {
415425
/// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
416426
#[inline]
427+
#[rustdoc_skip_body]
417428
fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
418429
tcp_listener.into_inner().into_socket().into_inner().into_inner()
419430
}
@@ -423,6 +434,7 @@ impl From<crate::net::TcpListener> for OwnedFd {
423434
#[cfg(not(target_os = "trusty"))]
424435
impl From<OwnedFd> for crate::net::TcpListener {
425436
#[inline]
437+
#[rustdoc_skip_body]
426438
fn from(owned_fd: OwnedFd) -> Self {
427439
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
428440
owned_fd,
@@ -434,6 +446,7 @@ impl From<OwnedFd> for crate::net::TcpListener {
434446
#[cfg(not(target_os = "trusty"))]
435447
impl AsFd for crate::net::UdpSocket {
436448
#[inline]
449+
#[rustdoc_skip_body]
437450
fn as_fd(&self) -> BorrowedFd<'_> {
438451
self.as_inner().socket().as_fd()
439452
}
@@ -444,6 +457,7 @@ impl AsFd for crate::net::UdpSocket {
444457
impl From<crate::net::UdpSocket> for OwnedFd {
445458
/// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
446459
#[inline]
460+
#[rustdoc_skip_body]
447461
fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
448462
udp_socket.into_inner().into_socket().into_inner().into_inner()
449463
}
@@ -453,6 +467,7 @@ impl From<crate::net::UdpSocket> for OwnedFd {
453467
#[cfg(not(target_os = "trusty"))]
454468
impl From<OwnedFd> for crate::net::UdpSocket {
455469
#[inline]
470+
#[rustdoc_skip_body]
456471
fn from(owned_fd: OwnedFd) -> Self {
457472
Self::from_inner(FromInner::from_inner(FromInner::from_inner(FromInner::from_inner(
458473
owned_fd,
@@ -613,6 +628,7 @@ impl<'a> AsFd for io::StderrLock<'a> {
613628
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
614629
#[cfg(not(target_os = "trusty"))]
615630
impl AsFd for io::PipeReader {
631+
#[rustdoc_skip_body]
616632
fn as_fd(&self) -> BorrowedFd<'_> {
617633
self.0.as_fd()
618634
}
@@ -621,6 +637,7 @@ impl AsFd for io::PipeReader {
621637
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
622638
#[cfg(not(target_os = "trusty"))]
623639
impl From<io::PipeReader> for OwnedFd {
640+
#[rustdoc_skip_body]
624641
fn from(pipe: io::PipeReader) -> Self {
625642
pipe.0.into_inner()
626643
}
@@ -629,6 +646,7 @@ impl From<io::PipeReader> for OwnedFd {
629646
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
630647
#[cfg(not(target_os = "trusty"))]
631648
impl AsFd for io::PipeWriter {
649+
#[rustdoc_skip_body]
632650
fn as_fd(&self) -> BorrowedFd<'_> {
633651
self.0.as_fd()
634652
}
@@ -637,6 +655,7 @@ impl AsFd for io::PipeWriter {
637655
#[stable(feature = "anonymous_pipe", since = "1.87.0")]
638656
#[cfg(not(target_os = "trusty"))]
639657
impl From<io::PipeWriter> for OwnedFd {
658+
#[rustdoc_skip_body]
640659
fn from(pipe: io::PipeWriter) -> Self {
641660
pipe.0.into_inner()
642661
}

0 commit comments

Comments
 (0)