summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_expand/src/mbe/transcribe.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-19 09:26:03 +0000
commit9918693037dce8aa4bb6f08741b6812923486c18 (patch)
tree21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_expand/src/mbe/transcribe.rs
parentReleasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff)
downloadrustc-9918693037dce8aa4bb6f08741b6812923486c18.tar.xz
rustc-9918693037dce8aa4bb6f08741b6812923486c18.zip
Merging upstream version 1.76.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_expand/src/mbe/transcribe.rs')
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs111
1 files changed, 71 insertions, 40 deletions
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index 15e7ab3fe..80fd82e03 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -7,7 +7,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, MatchedTokenTree,
use crate::mbe::{self, MetaVarExpr};
use rustc_ast::mut_visit::{self, MutVisitor};
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
-use rustc_ast::tokenstream::{DelimSpan, Spacing, TokenStream, TokenTree};
+use rustc_ast::tokenstream::{DelimSpacing, DelimSpan, Spacing, TokenStream, TokenTree};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{pluralize, PResult};
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
@@ -31,14 +31,24 @@ impl MutVisitor for Marker {
/// An iterator over the token trees in a delimited token tree (`{ ... }`) or a sequence (`$(...)`).
enum Frame<'a> {
- Delimited { tts: &'a [mbe::TokenTree], idx: usize, delim: Delimiter, span: DelimSpan },
- Sequence { tts: &'a [mbe::TokenTree], idx: usize, sep: Option<Token> },
+ Delimited {
+ tts: &'a [mbe::TokenTree],
+ idx: usize,
+ delim: Delimiter,
+ span: DelimSpan,
+ spacing: DelimSpacing,
+ },
+ Sequence {
+ tts: &'a [mbe::TokenTree],
+ idx: usize,
+ sep: Option<Token>,
+ },
}
impl<'a> Frame<'a> {
/// Construct a new frame around the delimited set of tokens.
- fn new(src: &'a mbe::Delimited, span: DelimSpan) -> Frame<'a> {
- Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span }
+ fn new(src: &'a mbe::Delimited, span: DelimSpan, spacing: DelimSpacing) -> Frame<'a> {
+ Frame::Delimited { tts: &src.tts, idx: 0, delim: src.delim, span, spacing }
}
}
@@ -89,8 +99,10 @@ pub(super) fn transcribe<'a>(
}
// We descend into the RHS (`src`), expanding things as we go. This stack contains the things
- // we have yet to expand/are still expanding. We start the stack off with the whole RHS.
- let mut stack: SmallVec<[Frame<'_>; 1]> = smallvec![Frame::new(&src, src_span)];
+ // we have yet to expand/are still expanding. We start the stack off with the whole RHS. The
+ // choice of spacing values doesn't matter.
+ let mut stack: SmallVec<[Frame<'_>; 1]> =
+ smallvec![Frame::new(src, src_span, DelimSpacing::new(Spacing::Alone, Spacing::Alone))];
// As we descend in the RHS, we will need to be able to match nested sequences of matchers.
// `repeats` keeps track of where we are in matching at each level, with the last element being
@@ -144,14 +156,19 @@ pub(super) fn transcribe<'a>(
// We are done processing a Delimited. If this is the top-level delimited, we are
// done. Otherwise, we unwind the result_stack to append what we have produced to
// any previous results.
- Frame::Delimited { delim, span, .. } => {
+ Frame::Delimited { delim, span, mut spacing, .. } => {
+ // Hack to force-insert a space after `]` in certain case.
+ // See discussion of the `hex-literal` crate in #114571.
+ if delim == Delimiter::Bracket {
+ spacing.close = Spacing::Alone;
+ }
if result_stack.is_empty() {
// No results left to compute! We are back at the top-level.
return Ok(TokenStream::new(result));
}
// Step back into the parent Delimited.
- let tree = TokenTree::Delimited(span, delim, TokenStream::new(result));
+ let tree = TokenTree::Delimited(span, spacing, delim, TokenStream::new(result));
result = result_stack.pop().unwrap();
result.push(tree);
}
@@ -166,7 +183,7 @@ pub(super) fn transcribe<'a>(
// and the matches in `interp` have the same shape. Otherwise, either the caller or the
// macro writer has made a mistake.
seq @ mbe::TokenTree::Sequence(_, delimited) => {
- match lockstep_iter_size(&seq, interp, &repeats) {
+ match lockstep_iter_size(seq, interp, &repeats) {
LockstepIterSize::Unconstrained => {
return Err(cx.create_err(NoSyntaxVarsExprRepeat { span: seq.span() }));
}
@@ -240,7 +257,7 @@ pub(super) fn transcribe<'a>(
// with modified syntax context. (I believe this supports nested macros).
marker.visit_span(&mut sp);
marker.visit_ident(&mut original_ident);
- result.push(TokenTree::token_alone(token::Dollar, sp));
+ result.push(TokenTree::token_joint_hidden(token::Dollar, sp));
result.push(TokenTree::Token(
Token::from_ast_ident(original_ident),
Spacing::Alone,
@@ -250,7 +267,7 @@ pub(super) fn transcribe<'a>(
// Replace meta-variable expressions with the result of their expansion.
mbe::TokenTree::MetaVarExpr(sp, expr) => {
- transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, &sp)?;
+ transcribe_metavar_expr(cx, expr, interp, &mut marker, &repeats, &mut result, sp)?;
}
// If we are entering a new delimiter, we push its contents to the `stack` to be
@@ -258,13 +275,14 @@ pub(super) fn transcribe<'a>(
// We will produce all of the results of the inside of the `Delimited` and then we will
// jump back out of the Delimited, pop the result_stack and add the new results back to
// the previous results (from outside the Delimited).
- mbe::TokenTree::Delimited(mut span, delimited) => {
+ mbe::TokenTree::Delimited(mut span, spacing, delimited) => {
mut_visit::visit_delim_span(&mut span, &mut marker);
stack.push(Frame::Delimited {
tts: &delimited.tts,
delim: delimited.delim,
idx: 0,
span,
+ spacing: *spacing,
});
result_stack.push(mem::take(&mut result));
}
@@ -374,7 +392,7 @@ fn lockstep_iter_size(
) -> LockstepIterSize {
use mbe::TokenTree;
match tree {
- TokenTree::Delimited(_, delimited) => {
+ TokenTree::Delimited(.., delimited) => {
delimited.tts.iter().fold(LockstepIterSize::Unconstrained, |size, tt| {
size.with(lockstep_iter_size(tt, interpolations, repeats))
})
@@ -422,7 +440,7 @@ fn lockstep_iter_size(
/// declared inside a single repetition and the index `1` implies two nested repetitions.
fn count_repetitions<'a>(
cx: &ExtCtxt<'a>,
- depth_opt: Option<usize>,
+ depth_user: usize,
mut matched: &NamedMatch,
repeats: &[(usize, usize)],
sp: &DelimSpan,
@@ -431,37 +449,45 @@ fn count_repetitions<'a>(
// (or at the top-level of `matched` if no depth is given).
fn count<'a>(
cx: &ExtCtxt<'a>,
- declared_lhs_depth: usize,
- depth_opt: Option<usize>,
+ depth_curr: usize,
+ depth_max: usize,
matched: &NamedMatch,
sp: &DelimSpan,
) -> PResult<'a, usize> {
match matched {
- MatchedTokenTree(_) | MatchedNonterminal(_) => {
- if declared_lhs_depth == 0 {
- return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
- }
- match depth_opt {
- None => Ok(1),
- Some(_) => Err(out_of_bounds_err(cx, declared_lhs_depth, sp.entire(), "count")),
- }
- }
+ MatchedTokenTree(_) | MatchedNonterminal(_) => Ok(1),
MatchedSeq(named_matches) => {
- let new_declared_lhs_depth = declared_lhs_depth + 1;
- match depth_opt {
- None => named_matches
- .iter()
- .map(|elem| count(cx, new_declared_lhs_depth, None, elem, sp))
- .sum(),
- Some(0) => Ok(named_matches.len()),
- Some(depth) => named_matches
+ if depth_curr == depth_max {
+ Ok(named_matches.len())
+ } else {
+ named_matches
.iter()
- .map(|elem| count(cx, new_declared_lhs_depth, Some(depth - 1), elem, sp))
- .sum(),
+ .map(|elem| count(cx, depth_curr + 1, depth_max, elem, sp))
+ .sum()
}
}
}
}
+
+ /// Maximum depth
+ fn depth(counter: usize, matched: &NamedMatch) -> usize {
+ match matched {
+ MatchedTokenTree(_) | MatchedNonterminal(_) => counter,
+ MatchedSeq(named_matches) => {
+ let rslt = counter + 1;
+ if let Some(elem) = named_matches.first() { depth(rslt, elem) } else { rslt }
+ }
+ }
+ }
+
+ let depth_max = depth(0, matched)
+ .checked_sub(1)
+ .and_then(|el| el.checked_sub(repeats.len()))
+ .unwrap_or_default();
+ if depth_user > depth_max {
+ return Err(out_of_bounds_err(cx, depth_max + 1, sp.entire(), "count"));
+ }
+
// `repeats` records all of the nested levels at which we are currently
// matching meta-variables. The meta-var-expr `count($x)` only counts
// matches that occur in this "subtree" of the `NamedMatch` where we
@@ -473,7 +499,12 @@ fn count_repetitions<'a>(
matched = &ads[idx];
}
}
- count(cx, 0, depth_opt, matched, sp)
+
+ if let MatchedTokenTree(_) | MatchedNonterminal(_) = matched {
+ return Err(cx.create_err(CountRepetitionMisplaced { span: sp.entire() }));
+ }
+
+ count(cx, depth_user, depth_max, matched, sp)
}
/// Returns a `NamedMatch` item declared on the LHS given an arbitrary [Ident]
@@ -505,7 +536,7 @@ fn out_of_bounds_err<'a>(
)
} else {
format!(
- "depth parameter on meta-variable expression `{ty}` \
+ "depth parameter of meta-variable expression `{ty}` \
must be less than {max}"
)
};
@@ -527,9 +558,9 @@ fn transcribe_metavar_expr<'a>(
span
};
match *expr {
- MetaVarExpr::Count(original_ident, depth_opt) => {
+ MetaVarExpr::Count(original_ident, depth) => {
let matched = matched_from_ident(cx, original_ident, interp)?;
- let count = count_repetitions(cx, depth_opt, matched, &repeats, sp)?;
+ let count = count_repetitions(cx, depth, matched, repeats, sp)?;
let tt = TokenTree::token_alone(
TokenKind::lit(token::Integer, sym::integer(count), None),
visited_span(),