Skip to content

Commit 7b766e0

Browse files
authored
Rollup merge of #148213 - GuillaumeGomez:fix-exit-of-expansion, r=yotamofek
Fix invalid tag closing when leaving expansion "original code" Fixes #148184. Problem was that in case an element inside the expansion's "original" element was not closed, this element would get its `pending_exit` field set to `true`, removing it when the next non-mergeable item gets pushed instead of being put inside it, and then next `exit_elem` would try to exit an empty class queue. r? ```@notriddle```
2 parents f7f128f + 8442380 commit 7b766e0

File tree

3 files changed

+58
-1
lines changed

3 files changed

+58
-1
lines changed

src/librustdoc/html/highlight.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,27 @@ impl<'a, F: Write> TokenHandler<'a, '_, F> {
427427
}
428428
}
429429
}
430+
431+
/// Used when we're done with the current expansion "original code" (ie code before expansion).
432+
/// We close all tags inside `Class::Original` and only keep the ones that were not closed yet.
433+
fn close_original_tag(&mut self) {
434+
let mut classes_to_reopen = Vec::new();
435+
while let Some(mut class_info) = self.class_stack.open_classes.pop() {
436+
if class_info.class == Class::Original {
437+
while let Some(class_info) = classes_to_reopen.pop() {
438+
self.class_stack.open_classes.push(class_info);
439+
}
440+
class_info.close_tag(self.out);
441+
return;
442+
}
443+
class_info.close_tag(self.out);
444+
if !class_info.pending_exit {
445+
class_info.closing_tag = None;
446+
classes_to_reopen.push(class_info);
447+
}
448+
}
449+
panic!("Didn't find `Class::Original` to close");
450+
}
430451
}
431452

432453
impl<F: Write> Drop for TokenHandler<'_, '_, F> {
@@ -484,7 +505,9 @@ fn end_expansion<'a, W: Write>(
484505
expanded_codes: &'a [ExpandedCode],
485506
span: Span,
486507
) -> Option<&'a ExpandedCode> {
487-
token_handler.class_stack.exit_elem();
508+
// We close `Class::Original` and everything open inside it.
509+
token_handler.close_original_tag();
510+
// Then we check if we have another macro expansion on the same line.
488511
let expansion = get_next_expansion(expanded_codes, token_handler.line, span);
489512
if expansion.is_none() {
490513
token_handler.close_expansion();
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
//@ force-host
2+
//@ no-prefer-dynamic
3+
//@ compile-flags: --crate-type proc-macro
4+
5+
#![crate_type = "proc-macro"]
6+
#![crate_name = "just_some_proc"]
7+
8+
extern crate proc_macro;
9+
10+
use proc_macro::TokenStream;
11+
12+
#[proc_macro_attribute]
13+
pub fn repro(_args: TokenStream, _input: TokenStream) -> TokenStream {
14+
"struct Repro;".parse().unwrap()
15+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Regression test for <https://github.com/rust-lang/rust/issues/148184>.
2+
// It ensures that the macro expansion correctly handles its "class stack".
3+
4+
//@ compile-flags: -Zunstable-options --generate-macro-expansion
5+
//@ aux-build:one-line-expand.rs
6+
7+
#![crate_name = "foo"]
8+
9+
extern crate just_some_proc;
10+
11+
//@ has 'src/foo/one-line-expand.rs.html'
12+
//@ has - '//*[@class="comment"]' '//'
13+
//@ has - '//*[@class="original"]' '#[just_some_proc::repro]'
14+
//@ has - '//*[@class="original"]/*[@class="attr"]' '#[just_some_proc::repro]'
15+
//@ has - '//code/*[@class="kw"]' 'struct '
16+
17+
//
18+
#[just_some_proc::repro]
19+
struct Repro;

0 commit comments

Comments
 (0)