Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/librustdoc/html/macro_expansion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ pub(crate) struct ExpandedCode {
/// As we go through the HIR visitor, if any span overlaps with another, they will
/// both be merged.
struct ExpandedCodeInfo {
original_span: Span,
/// Callsite of the macro.
span: Span,
/// Expanded macro source code (HTML escaped).
Expand Down Expand Up @@ -73,7 +74,12 @@ impl<'ast> ExpandedCodeVisitor<'ast> {
self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span))

@fmease fmease Aug 29, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Completely unrelated to this PR since it's preexisting but the position + manually indexing can easily be replaced by a find:

diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs
index 55ca93e601b..27741ea485a 100644
--- a/src/librustdoc/html/macro_expansion.rs
+++ b/src/librustdoc/html/macro_expansion.rs
@@ -70,10 +70,9 @@ fn handle_new_span<F: Fn() -> String>(&mut self, new_span: Span, f: F) {
             return;
         }
         let callsite_span = new_span.source_callsite();
-        if let Some(index) =
-            self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span))
+        if let Some(info) =
+            self.expanded_codes.iter_mut().find(|info| info.span.overlaps(callsite_span))
         {
-            let info = &mut self.expanded_codes[index];
             // If the new span we got has the exact same span information as a span already in the
             // list, it means it's generated from the same macro but is a different item, so we need
             // to add it as well.
@@ -86,12 +85,11 @@ fn handle_new_span<F: Fn() -> String>(&mut self, new_span: Span, f: F) {
                 info.code = f();
             } else {
                 // We push the new item after the existing one.
-                let expanded_code = &mut self.expanded_codes[index];
-                expanded_code.code.push('\n');
-                expanded_code.code.push_str(&f());
-                let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0));
-                let hi = BytePos(expanded_code.expanded_span.hi().0.max(new_span.hi().0));
-                expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi);
+                info.code.push('\n');
+                info.code.push_str(&f());
+                let lo = BytePos(info.expanded_span.lo().0.min(new_span.lo().0));
+                let hi = BytePos(info.expanded_span.hi().0.max(new_span.hi().0));
+                info.expanded_span = info.expanded_span.with_lo(lo).with_hi(hi);
             }
         } else {
             // We add a new item.

Noticed while reviewing #161944 and figuring out what original_span meant. Not worth a PR, so it's just a comment. idk. Edit: Added to my TODO list.

{
let info = &mut self.expanded_codes[index];
if new_span.contains(info.expanded_span) {
// If the new span we got has the exact same span information as a span already in the
// list, it means it's generated from the same macro but is a different item, so we need
// to add it as well.
let has_same_macro_origin =
new_span == info.original_span && callsite_span == info.span;
if !has_same_macro_origin && new_span.contains(info.expanded_span) {
// New macro expansion recursively contains the old one, so replace it.
info.span = callsite_span;
info.expanded_span = new_span;
Expand All @@ -84,12 +90,13 @@ impl<'ast> ExpandedCodeVisitor<'ast> {
expanded_code.code.push('\n');
expanded_code.code.push_str(&f());
let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0));
let hi = BytePos(expanded_code.expanded_span.hi().0.min(new_span.hi().0));
let hi = BytePos(expanded_code.expanded_span.hi().0.max(new_span.hi().0));
expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi);
}
} else {
// We add a new item.
self.expanded_codes.push(ExpandedCodeInfo {
original_span: new_span,
span: callsite_span,
code: f(),
expanded_span: new_span,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// This test ensures that when a macro call expands to multiple items,
// all of them are present in the macro expansion.
// Regression test for <https://github.com/rust-lang/rust/issues/157508>.

//@ compile-flags: -Zunstable-options --generate-macro-expansion

#![crate_name = "foo"]

macro_rules! print_skip {
($($t: ty),* $(,)?) => {$
(impl $t { fn f() {} })*
};
}

pub struct A;
pub struct B;

//@ has 'src/foo/multiple-items-in-one-macro-call.rs.html'
// Both `impl A` and `impl B` should be here.
//@ matches - '//*[@class="expansion"]/*[@class="expanded"]' \
// '^impl A \{\s+fn f\(\) \{\}\n\}\nimpl B \{\s+fn f\(\) \{\}\n\}$'
print_skip!(A, B);
Loading