Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 71337f6

Browse files
committed
fix: Fix concat_bytes! expansion
1 parent 143203b commit 71337f6

File tree

4 files changed

+61
-7
lines changed

4 files changed

+61
-7
lines changed

crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -468,12 +468,12 @@ macro_rules! concat_bytes {}
468468
469469
fn main() { concat_bytes!(b'A', b"BC", [68, b'E', 70]); }
470470
"##,
471-
expect![[r##"
471+
expect![[r#"
472472
#[rustc_builtin_macro]
473473
macro_rules! concat_bytes {}
474474
475475
fn main() { [b'A', 66, 67, 68, b'E', 70]; }
476-
"##]],
476+
"#]],
477477
);
478478
}
479479

crates/hir-def/src/macro_expansion_tests/mbe/regression.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,3 +1004,29 @@ fn main() {
10041004
"##]],
10051005
);
10061006
}
1007+
1008+
#[test]
1009+
fn eager_concat_bytes_panic() {
1010+
check(
1011+
r#"
1012+
#[rustc_builtin_macro]
1013+
#[macro_export]
1014+
macro_rules! concat_bytes {}
1015+
1016+
fn main() {
1017+
let x = concat_bytes!(2);
1018+
}
1019+
1020+
"#,
1021+
expect![[r#"
1022+
#[rustc_builtin_macro]
1023+
#[macro_export]
1024+
macro_rules! concat_bytes {}
1025+
1026+
fn main() {
1027+
let x = /* error: unexpected token in input */[];
1028+
}
1029+
1030+
"#]],
1031+
);
1032+
}

crates/hir-expand/src/builtin_fn_macro.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use base_db::{
66
};
77
use cfg::CfgExpr;
88
use either::Either;
9+
use itertools::Itertools;
910
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
1011
use syntax::{
1112
ast::{self, AstToken},
@@ -491,8 +492,25 @@ fn concat_bytes_expand(
491492
}
492493
}
493494
}
494-
let ident = tt::Ident { text: bytes.join(", ").into(), span };
495-
ExpandResult { value: quote!(span =>[#ident]), err }
495+
let value = tt::Subtree {
496+
delimiter: tt::Delimiter { open: span, close: span, kind: tt::DelimiterKind::Bracket },
497+
token_trees: {
498+
Itertools::intersperse_with(
499+
bytes.into_iter().map(|it| {
500+
tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text: it.into(), span }))
501+
}),
502+
|| {
503+
tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
504+
char: ',',
505+
spacing: tt::Spacing::Alone,
506+
span,
507+
}))
508+
},
509+
)
510+
.collect()
511+
},
512+
};
513+
ExpandResult { value, err }
496514
}
497515

498516
fn concat_bytes_expand_subtree(

crates/mbe/src/token_map.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use std::hash::Hash;
44

5-
use stdx::itertools::Itertools;
5+
use stdx::{always, itertools::Itertools};
66
use syntax::{TextRange, TextSize};
77
use tt::Span;
88

@@ -21,13 +21,23 @@ impl<S: Span> SpanMap<S> {
2121
/// Finalizes the [`SpanMap`], shrinking its backing storage and validating that the offsets are
2222
/// in order.
2323
pub fn finish(&mut self) {
24-
assert!(self.spans.iter().tuple_windows().all(|(a, b)| a.0 < b.0));
24+
always!(
25+
self.spans.iter().tuple_windows().all(|(a, b)| a.0 < b.0),
26+
"spans are not in order"
27+
);
2528
self.spans.shrink_to_fit();
2629
}
2730

2831
/// Pushes a new span onto the [`SpanMap`].
2932
pub fn push(&mut self, offset: TextSize, span: S) {
30-
debug_assert!(self.spans.last().map_or(true, |&(last_offset, _)| last_offset < offset));
33+
if cfg!(debug_assertions) {
34+
if let Some(&(last_offset, _)) = self.spans.last() {
35+
assert!(
36+
last_offset < offset,
37+
"last_offset({last_offset:?}) must be smaller than offset({offset:?})"
38+
);
39+
}
40+
}
3141
self.spans.push((offset, span));
3242
}
3343

0 commit comments

Comments
 (0)