Skip to content

Commit 7a19392

Browse files
committed
Auto merge of rust-lang#77862 - danielhenrymantilla:rustdoc/fix-macros_2_0-paths, r=jyn514,petrochenkov
Rustdoc: Fix macros 2.0 and built-in derives being shown at the wrong path Fixes rust-lang#74355 - ~~waiting on author + draft PR since my code ought to be cleaned up _w.r.t._ the way I avoid the `.unwrap()`s:~~ - ~~dummy items may avoid the first `?`,~~ - ~~but within the module traversal some tests did fail (hence the second `?`), meaning the crate did not possess the exact path of the containing module (`extern` / `impl` blocks maybe? I'll look into that).~~ r? `@jyn514`
2 parents 7cf2056 + bceb173 commit 7a19392

File tree

6 files changed

+163
-13
lines changed

6 files changed

+163
-13
lines changed

compiler/rustc_privacy/src/lib.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -832,10 +832,15 @@ impl Visitor<'tcx> for EmbargoVisitor<'tcx> {
832832
}
833833

834834
fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) {
835+
// Non-opaque macros cannot make other items more accessible than they already are.
835836
if attr::find_transparency(&self.tcx.sess, &md.attrs, md.ast.macro_rules).0
836837
!= Transparency::Opaque
837838
{
838-
self.update(md.hir_id, Some(AccessLevel::Public));
839+
// `#[macro_export]`-ed `macro_rules!` are `Public` since they
840+
// ignore their containing path to always appear at the crate root.
841+
if md.ast.macro_rules {
842+
self.update(md.hir_id, Some(AccessLevel::Public));
843+
}
839844
return;
840845
}
841846

library/std/src/prelude/v1.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -41,17 +41,17 @@ pub use crate::result::Result::{self, Err, Ok};
4141
pub use core::prelude::v1::{
4242
asm, assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
4343
format_args_nl, global_asm, include, include_bytes, include_str, line, llvm_asm, log_syntax,
44-
module_path, option_env, stringify, trace_macros,
44+
module_path, option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord,
45+
PartialEq, PartialOrd,
4546
};
4647

47-
// FIXME: Attribute and derive macros are not documented because for them rustdoc generates
48+
// FIXME: Attribute and internal derive macros are not documented because for them rustdoc generates
4849
// dead links which fail link checker testing.
4950
#[stable(feature = "builtin_macro_prelude", since = "1.38.0")]
5051
#[allow(deprecated)]
5152
#[doc(hidden)]
5253
pub use core::prelude::v1::{
53-
bench, global_allocator, test, test_case, Clone, Copy, Debug, Default, Eq, Hash, Ord,
54-
PartialEq, PartialOrd, RustcDecodable, RustcEncodable,
54+
bench, global_allocator, test, test_case, RustcDecodable, RustcEncodable,
5555
};
5656

5757
#[unstable(

src/librustdoc/clean/inline.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,17 @@ crate fn record_extern_fqn(cx: &DocContext<'_>, did: DefId, kind: clean::TypeKin
169169
if !s.is_empty() { Some(s) } else { None }
170170
});
171171
let fqn = if let clean::TypeKind::Macro = kind {
172-
vec![crate_name, relative.last().expect("relative was empty")]
172+
// Check to see if it is a macro 2.0 or built-in macro
173+
if matches!(
174+
cx.enter_resolver(|r| r.cstore().load_macro_untracked(did, cx.sess())),
175+
LoadedMacro::MacroDef(def, _)
176+
if matches!(&def.kind, ast::ItemKind::MacroDef(ast_def)
177+
if !ast_def.macro_rules)
178+
) {
179+
once(crate_name).chain(relative).collect()
180+
} else {
181+
vec![crate_name, relative.last().expect("relative was empty")]
182+
}
173183
} else {
174184
once(crate_name).chain(relative).collect()
175185
};

src/librustdoc/visit_ast.rs

+47-7
Original file line numberDiff line numberDiff line change
@@ -61,20 +61,60 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> {
6161
}
6262

6363
crate fn visit(mut self, krate: &'tcx hir::Crate<'_>) -> Module<'tcx> {
64-
let mut module = self.visit_mod_contents(
64+
let mut top_level_module = self.visit_mod_contents(
6565
krate.item.span,
6666
&Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public },
6767
hir::CRATE_HIR_ID,
6868
&krate.item.module,
6969
None,
7070
);
71-
// Attach the crate's exported macros to the top-level module:
72-
module.macros.extend(krate.exported_macros.iter().map(|def| (def, None)));
73-
module.is_crate = true;
74-
71+
top_level_module.is_crate = true;
72+
// Attach the crate's exported macros to the top-level module.
73+
// In the case of macros 2.0 (`pub macro`), and for built-in `derive`s or attributes as
74+
// well (_e.g._, `Copy`), these are wrongly bundled in there too, so we need to fix that by
75+
// moving them back to their correct locations.
76+
'exported_macros: for def in krate.exported_macros {
77+
// The `def` of a macro in `exported_macros` should correspond to either:
78+
// - a `#[macro_export] macro_rules!` macro,
79+
// - a built-in `derive` (or attribute) macro such as the ones in `::core`,
80+
// - a `pub macro`.
81+
// Only the last two need to be fixed, thus:
82+
if def.ast.macro_rules {
83+
top_level_module.macros.push((def, None));
84+
continue 'exported_macros;
85+
}
86+
let tcx = self.cx.tcx;
87+
// Note: this is not the same as `.parent_module()`. Indeed, the latter looks
88+
// for the closest module _ancestor_, which is not necessarily a direct parent
89+
// (since a direct parent isn't necessarily a module, c.f. #77828).
90+
let macro_parent_def_id = {
91+
use rustc_middle::ty::DefIdTree;
92+
tcx.parent(tcx.hir().local_def_id(def.hir_id).to_def_id()).unwrap()
93+
};
94+
let macro_parent_path = tcx.def_path(macro_parent_def_id);
95+
// HACK: rustdoc has no way to lookup `doctree::Module`s by their HirId. Instead,
96+
// lookup the module by its name, by looking at each path segment one at a time.
97+
let mut cur_mod = &mut top_level_module;
98+
for path_segment in macro_parent_path.data {
99+
// Path segments may refer to a module (in which case they belong to the type
100+
// namespace), which is _necessary_ for the macro to be accessible outside it
101+
// (no "associated macros" as of yet). Else we bail with an outer `continue`.
102+
let path_segment_ty_ns = match path_segment.data {
103+
rustc_hir::definitions::DefPathData::TypeNs(symbol) => symbol,
104+
_ => continue 'exported_macros,
105+
};
106+
// Descend into the child module that matches this path segment (if any).
107+
match cur_mod.mods.iter_mut().find(|child| child.name == Some(path_segment_ty_ns)) {
108+
Some(child_mod) => cur_mod = &mut *child_mod,
109+
None => continue 'exported_macros,
110+
}
111+
}
112+
let cur_mod_def_id = tcx.hir().local_def_id(cur_mod.id).to_def_id();
113+
assert_eq!(cur_mod_def_id, macro_parent_def_id);
114+
cur_mod.macros.push((def, None));
115+
}
75116
self.cx.renderinfo.get_mut().exact_paths = self.exact_paths;
76-
77-
module
117+
top_level_module
78118
}
79119

80120
fn visit_mod_contents(
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// edition:2018
2+
3+
#![feature(decl_macro)]
4+
#![crate_name = "external_crate"]
5+
6+
pub mod some_module {
7+
/* == Make sure the logic is not affected by a re-export == */
8+
mod private {
9+
pub macro external_macro() {}
10+
}
11+
12+
pub use private::external_macro;
13+
}
+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// aux-build:macro_pub_in_module.rs
2+
// edition:2018
3+
// build-aux-docs
4+
5+
//! See issue #74355
6+
#![feature(decl_macro, no_core, rustc_attrs)]
7+
#![crate_name = "krate"]
8+
#![no_core]
9+
10+
// @has external_crate/some_module/macro.external_macro.html
11+
// @!has external_crate/macro.external_macro.html
12+
extern crate external_crate;
13+
14+
pub mod inner {
15+
// @has krate/inner/macro.raw_const.html
16+
// @!has krate/macro.raw_const.html
17+
pub macro raw_const() {}
18+
19+
// @has krate/inner/macro.test.html
20+
// @!has krate/macro.test.html
21+
#[rustc_builtin_macro]
22+
pub macro test($item:item) {}
23+
24+
// @has krate/inner/macro.Clone.html
25+
// @!has krate/macro.Clone.html
26+
#[rustc_builtin_macro]
27+
pub macro Clone($item:item) {}
28+
29+
// Make sure the logic is not affected by re-exports.
30+
mod unrenamed {
31+
// @!has krate/macro.unrenamed.html
32+
#[rustc_macro_transparency = "semitransparent"]
33+
pub macro unrenamed() {}
34+
}
35+
// @has krate/inner/macro.unrenamed.html
36+
pub use unrenamed::unrenamed;
37+
38+
mod private {
39+
// @!has krate/macro.m.html
40+
pub macro m() {}
41+
}
42+
// @has krate/inner/macro.renamed.html
43+
// @!has krate/macro.renamed.html
44+
pub use private::m as renamed;
45+
46+
mod private2 {
47+
// @!has krate/macro.m2.html
48+
pub macro m2() {}
49+
}
50+
use private2 as renamed_mod;
51+
// @has krate/inner/macro.m2.html
52+
pub use renamed_mod::m2;
53+
54+
// @has krate/inner/macro.external_macro.html
55+
// @!has krate/macro.external_macro.html
56+
pub use ::external_crate::some_module::external_macro;
57+
}
58+
59+
// Namespaces: Make sure the logic does not mix up a function name with a module name…
60+
fn both_fn_and_mod() {
61+
// @!has krate/macro.in_both_fn_and_mod.html
62+
pub macro in_both_fn_and_mod() {}
63+
}
64+
pub mod both_fn_and_mod {
65+
// @!has krate/both_fn_and_mod/macro.in_both_fn_and_mod.html
66+
}
67+
68+
const __: () = {
69+
// @!has krate/macro.in_both_const_and_mod.html
70+
pub macro in_both_const_and_mod() {}
71+
};
72+
pub mod __ {
73+
// @!has krate/__/macro.in_both_const_and_mod.html
74+
}
75+
76+
enum Enum {
77+
Crazy = {
78+
// @!has krate/macro.this_is_getting_weird.html;
79+
pub macro this_is_getting_weird() {}
80+
42
81+
},
82+
}

0 commit comments

Comments
 (0)