Unnamed repository; edit this file 'description' to name the repository.
fix: Fix `concat_bytes!` expansion
Lukas Wirth 2023-12-08
parent 143203b · commit 71337f6
-rw-r--r--crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs4
-rw-r--r--crates/hir-def/src/macro_expansion_tests/mbe/regression.rs26
-rw-r--r--crates/hir-expand/src/builtin_fn_macro.rs22
-rw-r--r--crates/mbe/src/token_map.rs16
4 files changed, 61 insertions, 7 deletions
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 106ead83fa..514219ee71 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -468,12 +468,12 @@ macro_rules! concat_bytes {}
fn main() { concat_bytes!(b'A', b"BC", [68, b'E', 70]); }
"##,
- expect![[r##"
+ expect![[r#"
#[rustc_builtin_macro]
macro_rules! concat_bytes {}
fn main() { [b'A', 66, 67, 68, b'E', 70]; }
-"##]],
+"#]],
);
}
diff --git a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
index 2886b2a366..9010050ee6 100644
--- a/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
+++ b/crates/hir-def/src/macro_expansion_tests/mbe/regression.rs
@@ -1004,3 +1004,29 @@ fn main() {
"##]],
);
}
+
+#[test]
+fn eager_concat_bytes_panic() {
+ check(
+ r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! concat_bytes {}
+
+fn main() {
+ let x = concat_bytes!(2);
+}
+
+"#,
+ expect![[r#"
+#[rustc_builtin_macro]
+#[macro_export]
+macro_rules! concat_bytes {}
+
+fn main() {
+ let x = /* error: unexpected token in input */[];
+}
+
+"#]],
+ );
+}
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index 903c21c84e..c8f04bfee5 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -6,6 +6,7 @@ use base_db::{
};
use cfg::CfgExpr;
use either::Either;
+use itertools::Itertools;
use mbe::{parse_exprs_with_sep, parse_to_token_tree};
use syntax::{
ast::{self, AstToken},
@@ -491,8 +492,25 @@ fn concat_bytes_expand(
}
}
}
- let ident = tt::Ident { text: bytes.join(", ").into(), span };
- ExpandResult { value: quote!(span =>[#ident]), err }
+ let value = tt::Subtree {
+ delimiter: tt::Delimiter { open: span, close: span, kind: tt::DelimiterKind::Bracket },
+ token_trees: {
+ Itertools::intersperse_with(
+ bytes.into_iter().map(|it| {
+ tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { text: it.into(), span }))
+ }),
+ || {
+ tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+ char: ',',
+ spacing: tt::Spacing::Alone,
+ span,
+ }))
+ },
+ )
+ .collect()
+ },
+ };
+ ExpandResult { value, err }
}
fn concat_bytes_expand_subtree(
diff --git a/crates/mbe/src/token_map.rs b/crates/mbe/src/token_map.rs
index 28b39b4f1e..7d15812f8c 100644
--- a/crates/mbe/src/token_map.rs
+++ b/crates/mbe/src/token_map.rs
@@ -2,7 +2,7 @@
use std::hash::Hash;
-use stdx::itertools::Itertools;
+use stdx::{always, itertools::Itertools};
use syntax::{TextRange, TextSize};
use tt::Span;
@@ -21,13 +21,23 @@ impl<S: Span> SpanMap<S> {
/// Finalizes the [`SpanMap`], shrinking its backing storage and validating that the offsets are
/// in order.
pub fn finish(&mut self) {
- assert!(self.spans.iter().tuple_windows().all(|(a, b)| a.0 < b.0));
+ always!(
+ self.spans.iter().tuple_windows().all(|(a, b)| a.0 < b.0),
+ "spans are not in order"
+ );
self.spans.shrink_to_fit();
}
/// Pushes a new span onto the [`SpanMap`].
pub fn push(&mut self, offset: TextSize, span: S) {
- debug_assert!(self.spans.last().map_or(true, |&(last_offset, _)| last_offset < offset));
+ if cfg!(debug_assertions) {
+ if let Some(&(last_offset, _)) = self.spans.last() {
+ assert!(
+ last_offset < offset,
+ "last_offset({last_offset:?}) must be smaller than offset({offset:?})"
+ );
+ }
+ }
self.spans.push((offset, span));
}