diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-19 09:26:03 +0000 |
commit | 9918693037dce8aa4bb6f08741b6812923486c18 (patch) | |
tree | 21d2b40bec7e6a7ea664acee056eb3d08e15a1cf /compiler/rustc_expand/src/mbe | |
parent | Releasing progress-linux version 1.75.0+dfsg1-5~progress7.99u1. (diff) | |
download | rustc-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')
-rw-r--r-- | compiler/rustc_expand/src/mbe/diagnostics.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/macro_check.rs | 25 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/macro_parser.rs | 10 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/macro_rules.rs | 75 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/metavar_expr.rs | 53 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/quoted.rs | 34 | ||||
-rw-r--r-- | compiler/rustc_expand/src/mbe/transcribe.rs | 111 |
7 files changed, 186 insertions, 132 deletions
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index e06037564..8f80e6e29 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -34,7 +34,7 @@ pub(super) fn failed_to_match_macro<'cx>( if try_success_result.is_ok() { // Nonterminal parser recovery might turn failed matches into successful ones, // but for that it must have emitted an error already - tracker.cx.sess.delay_span_bug(sp, "Macro matching returned a success on the second try"); + tracker.cx.sess.span_delayed_bug(sp, "Macro matching returned a success on the second try"); } if let Some(result) = tracker.result { @@ -67,6 +67,12 @@ pub(super) fn failed_to_match_macro<'cx>( && (matches!(expected_token.kind, TokenKind::Interpolated(_)) || matches!(token.kind, TokenKind::Interpolated(_))) { + if let TokenKind::Interpolated(node) = &expected_token.kind { + err.span_label(node.1, ""); + } + if let TokenKind::Interpolated(node) = &token.kind { + err.span_label(node.1, ""); + } err.note("captured metavariables except for `:tt`, `:ident` and `:lifetime` cannot be compared to other tokens"); err.note("see <https://doc.rust-lang.org/nightly/reference/macros-by-example.html#forwarding-a-matched-fragment> for more information"); @@ -145,7 +151,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, Success(_) => { // Nonterminal parser recovery might turn failed matches into successful ones, // but for that it must have emitted an error already - self.cx.sess.delay_span_bug( + self.cx.sess.span_delayed_bug( self.root_span, "should not collect detailed info for successful macro match", ); diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index 95f5bb2d2..e66cfbe6f 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -205,7 +205,7 @@ pub(super) fn check_meta_variables( rhses: &[TokenTree], ) -> bool { if lhses.len() != rhses.len() { - sess.span_diagnostic.span_bug(span, "length mismatch between LHSes and RHSes") + sess.dcx.span_bug(span, "length mismatch between LHSes and RHSes") } let mut valid = true; for (lhs, rhs) in iter::zip(lhses, rhses) { @@ -244,7 +244,7 @@ fn check_binders( // MetaVar(fragment) and not as MetaVarDecl(y, fragment). TokenTree::MetaVar(span, name) => { if macros.is_empty() { - sess.span_diagnostic.span_bug(span, "unexpected MetaVar in lhs"); + sess.dcx.span_bug(span, "unexpected MetaVar in lhs"); } let name = MacroRulesNormalizedIdent::new(name); // There are 3 possibilities: @@ -275,14 +275,13 @@ fn check_binders( ); } if !macros.is_empty() { - sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in nested lhs"); + sess.dcx.span_bug(span, "unexpected MetaVarDecl in nested lhs"); } let name = MacroRulesNormalizedIdent::new(name); if let Some(prev_info) = get_binder_info(macros, binders, name) { // Duplicate binders at the top-level macro definition are errors. The lint is only // for nested macro definitions. - sess.span_diagnostic - .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }); + sess.dcx.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }); *valid = false; } else { binders.insert(name, BinderInfo { span, ops: ops.into() }); @@ -290,7 +289,7 @@ fn check_binders( } // `MetaVarExpr` can not appear in the LHS of a macro arm TokenTree::MetaVarExpr(..) => {} - TokenTree::Delimited(_, ref del) => { + TokenTree::Delimited(.., ref del) => { for tt in &del.tts { check_binders(sess, node_id, tt, macros, binders, ops, valid); } @@ -341,7 +340,7 @@ fn check_occurrences( match *rhs { TokenTree::Token(..) => {} TokenTree::MetaVarDecl(span, _name, _kind) => { - sess.span_diagnostic.span_bug(span, "unexpected MetaVarDecl in rhs") + sess.dcx.span_bug(span, "unexpected MetaVarDecl in rhs") } TokenTree::MetaVar(span, name) => { let name = MacroRulesNormalizedIdent::new(name); @@ -353,7 +352,7 @@ fn check_occurrences( }; check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name); } - TokenTree::Delimited(_, ref del) => { + TokenTree::Delimited(.., ref del) => { check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid); } TokenTree::Sequence(_, ref seq) => { @@ -435,8 +434,8 @@ fn check_nested_occurrences( // We check that the meta-variable is correctly used. check_occurrences(sess, node_id, tt, macros, binders, ops, valid); } - (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(_, del)) - | (NestedMacroState::MacroName, TokenTree::Delimited(_, del)) + (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del)) + | (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Brace => { let macro_rules = state == NestedMacroState::MacroRulesNotName; @@ -466,7 +465,7 @@ fn check_nested_occurrences( // We check that the meta-variable is correctly used. check_occurrences(sess, node_id, tt, macros, binders, ops, valid); } - (NestedMacroState::MacroName, TokenTree::Delimited(_, del)) + (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Parenthesis => { state = NestedMacroState::MacroNameParen; @@ -481,7 +480,7 @@ fn check_nested_occurrences( valid, ); } - (NestedMacroState::MacroNameParen, TokenTree::Delimited(_, del)) + (NestedMacroState::MacroNameParen, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Brace => { state = NestedMacroState::Empty; @@ -650,6 +649,6 @@ fn buffer_lint( ) { // Macros loaded from other crates have dummy node ids. if node_id != DUMMY_NODE_ID { - sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message); + sess.buffer_lint(META_VARIABLE_MISUSE, span, node_id, message); } } diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs index 7e85beaad..b248a1fe3 100644 --- a/compiler/rustc_expand/src/mbe/macro_parser.rs +++ b/compiler/rustc_expand/src/mbe/macro_parser.rs @@ -184,7 +184,7 @@ pub(super) fn compute_locs(matcher: &[TokenTree]) -> Vec<MatcherLoc> { TokenTree::Token(token) => { locs.push(MatcherLoc::Token { token: token.clone() }); } - TokenTree::Delimited(span, delimited) => { + TokenTree::Delimited(span, _, delimited) => { let open_token = Token::new(token::OpenDelim(delimited.delim), span.open); let close_token = Token::new(token::CloseDelim(delimited.delim), span.close); @@ -335,7 +335,7 @@ pub(super) fn count_metavar_decls(matcher: &[TokenTree]) -> usize { .map(|tt| match tt { TokenTree::MetaVarDecl(..) => 1, TokenTree::Sequence(_, seq) => seq.num_captures, - TokenTree::Delimited(_, delim) => count_metavar_decls(&delim.tts), + TokenTree::Delimited(.., delim) => count_metavar_decls(&delim.tts), TokenTree::Token(..) => 0, TokenTree::MetaVar(..) | TokenTree::MetaVarExpr(..) => unreachable!(), }) @@ -397,7 +397,7 @@ pub(crate) enum NamedMatch { MatchedTokenTree(rustc_ast::tokenstream::TokenTree), // A metavar match of any type other than `tt`. - MatchedNonterminal(Lrc<Nonterminal>), + MatchedNonterminal(Lrc<(Nonterminal, rustc_span::Span)>), } /// Performs a token equality check, ignoring syntax context (that is, an unhygienic comparison) @@ -483,7 +483,7 @@ impl TtParser { if matches!(t, Token { kind: DocComment(..), .. }) { mp.idx += 1; self.cur_mps.push(mp); - } else if token_name_eq(&t, token) { + } else if token_name_eq(t, token) { mp.idx += 1; self.next_mps.push(mp); } @@ -692,7 +692,7 @@ impl TtParser { Ok(nt) => nt, }; let m = match nt { - ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new(nt)), + ParseNtResult::Nt(nt) => MatchedNonterminal(Lrc::new((nt, span))), ParseNtResult::Tt(tt) => MatchedTokenTree(tt), }; mp.push_match(next_metavar, seq_depth, m); diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index ebdd3cb54..44f10e7d3 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -207,13 +207,13 @@ fn expand_macro<'cx>( match try_success_result { Ok((i, named_matches)) => { let (rhs, rhs_span): (&mbe::Delimited, DelimSpan) = match &rhses[i] { - mbe::TokenTree::Delimited(span, delimited) => (&delimited, *span), + mbe::TokenTree::Delimited(span, _, delimited) => (&delimited, *span), _ => cx.span_bug(sp, "malformed macro rhs"), }; let arm_span = rhses[i].span(); // rhs has holes ( `$id` and `$(...)` that need filled) - let mut tts = match transcribe(cx, &named_matches, &rhs, rhs_span, transparency) { + let mut tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { Ok(tts) => tts, Err(mut err) => { err.emit(); @@ -236,6 +236,13 @@ fn expand_macro<'cx>( target_sp.open = source_sp.open.with_ctxt(ctxt); target_sp.close = source_sp.close.with_ctxt(ctxt); } + ( + TokenTree::Delimited(target_sp, ..), + mbe::TokenTree::MetaVar(source_sp, ..), + ) => { + target_sp.open = source_sp.with_ctxt(ctxt); + target_sp.close = source_sp.with_ctxt(ctxt).shrink_to_hi(); + } _ => { let sp = rhs_tt.span().with_ctxt(ctxt); tt.set_span(sp); @@ -395,7 +402,7 @@ pub fn compile_declarative_macro( }; let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new()); - let diag = &sess.parse_sess.span_diagnostic; + let dcx = &sess.parse_sess.dcx; let lhs_nm = Ident::new(sym::lhs, def.span); let rhs_nm = Ident::new(sym::rhs, def.span); let tt_spec = Some(NonterminalKind::TT); @@ -475,17 +482,14 @@ pub fn compile_declarative_macro( let s = parse_failure_msg(&token); let sp = token.span.substitute_dummy(def.span); - let mut err = sess.parse_sess.span_diagnostic.struct_span_err(sp, s); + let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(&mut err, sess.source_map(), sp); err.emit(); return dummy_syn_ext(); } Error(sp, msg) => { - sess.parse_sess - .span_diagnostic - .struct_span_err(sp.substitute_dummy(def.span), msg) - .emit(); + sess.dcx().struct_span_err(sp.substitute_dummy(def.span), msg).emit(); return dummy_syn_ext(); } ErrorReported(_) => { @@ -511,13 +515,13 @@ pub fn compile_declarative_macro( ) .pop() .unwrap(); - valid &= check_lhs_nt_follows(&sess.parse_sess, &def, &tt); + valid &= check_lhs_nt_follows(&sess.parse_sess, def, &tt); return tt; } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs") + sess.dcx().span_bug(def.span, "wrong-structured lhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"), + _ => sess.dcx().span_bug(def.span, "wrong-structured lhs"), }; let rhses = match &argument_map[&MacroRulesNormalizedIdent::new(rhs_nm)] { @@ -536,10 +540,10 @@ pub fn compile_declarative_macro( .pop() .unwrap(); } - sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs") + sess.dcx().span_bug(def.span, "wrong-structured rhs") }) .collect::<Vec<mbe::TokenTree>>(), - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"), + _ => sess.dcx().span_bug(def.span, "wrong-structured rhs"), }; for rhs in &rhses { @@ -556,10 +560,10 @@ pub fn compile_declarative_macro( let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); match transparency_error { Some(TransparencyError::UnknownTransparency(value, span)) => { - diag.span_err(span, format!("unknown macro transparency: `{value}`")); + dcx.span_err(span, format!("unknown macro transparency: `{value}`")); } Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => { - diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes"); + dcx.span_err(vec![old_span, new_span], "multiple macro transparency attributes"); } None => {} } @@ -592,10 +596,10 @@ pub fn compile_declarative_macro( .map(|lhs| { // Ignore the delimiters around the matcher. match lhs { - mbe::TokenTree::Delimited(_, delimited) => { + mbe::TokenTree::Delimited(.., delimited) => { mbe::macro_parser::compute_locs(&delimited.tts) } - _ => sess.parse_sess.span_diagnostic.span_bug(def.span, "malformed macro lhs"), + _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), } }) .collect() @@ -618,11 +622,11 @@ pub fn compile_declarative_macro( fn check_lhs_nt_follows(sess: &ParseSess, def: &ast::Item, lhs: &mbe::TokenTree) -> bool { // lhs is going to be like TokenTree::Delimited(...), where the // entire lhs is those tts. Or, it can be a "bare sequence", not wrapped in parens. - if let mbe::TokenTree::Delimited(_, delimited) = lhs { + if let mbe::TokenTree::Delimited(.., delimited) = lhs { check_matcher(sess, def, &delimited.tts) } else { let msg = "invalid macro matcher; matchers must be contained in balanced delimiters"; - sess.span_diagnostic.span_err(lhs.span(), msg); + sess.dcx.span_err(lhs.span(), msg); false } // we don't abort on errors on rejection, the driver will do that for us @@ -648,10 +652,7 @@ fn is_empty_token_tree(sess: &ParseSess, seq: &mbe::SequenceRepetition) -> bool iter.next(); } let span = t.span.to(now.span); - sess.span_diagnostic.span_note_without_error( - span, - "doc comments are ignored in matcher position", - ); + sess.dcx.span_note(span, "doc comments are ignored in matcher position"); } mbe::TokenTree::Sequence(_, sub_seq) if (sub_seq.kleene.op == mbe::KleeneOp::ZeroOrMore @@ -673,7 +674,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) | TokenTree::MetaVarExpr(..) => (), - TokenTree::Delimited(_, del) => { + TokenTree::Delimited(.., del) => { if !check_lhs_no_empty_seq(sess, &del.tts) { return false; } @@ -681,7 +682,7 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[mbe::TokenTree]) -> bool { TokenTree::Sequence(span, seq) => { if is_empty_token_tree(sess, seq) { let sp = span.entire(); - sess.span_diagnostic.span_err(sp, "repetition matches empty token tree"); + sess.dcx.span_err(sp, "repetition matches empty token tree"); return false; } if !check_lhs_no_empty_seq(sess, &seq.tts) { @@ -698,7 +699,7 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool { match *rhs { mbe::TokenTree::Delimited(..) => return true, _ => { - sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"); + sess.dcx.span_err(rhs.span(), "macro rhs must be delimited"); } } false @@ -707,21 +708,21 @@ fn check_rhs(sess: &ParseSess, rhs: &mbe::TokenTree) -> bool { fn check_matcher(sess: &ParseSess, def: &ast::Item, matcher: &[mbe::TokenTree]) -> bool { let first_sets = FirstSets::new(matcher); let empty_suffix = TokenSet::empty(); - let err = sess.span_diagnostic.err_count(); + let err = sess.dcx.err_count(); check_matcher_core(sess, def, &first_sets, matcher, &empty_suffix); - err == sess.span_diagnostic.err_count() + err == sess.dcx.err_count() } fn has_compile_error_macro(rhs: &mbe::TokenTree) -> bool { match rhs { - mbe::TokenTree::Delimited(_sp, d) => { + mbe::TokenTree::Delimited(.., d) => { let has_compile_error = d.tts.array_windows::<3>().any(|[ident, bang, args]| { if let mbe::TokenTree::Token(ident) = ident && let TokenKind::Ident(ident, _) = ident.kind && ident == sym::compile_error && let mbe::TokenTree::Token(bang) = bang && let TokenKind::Not = bang.kind - && let mbe::TokenTree::Delimited(_, del) = args + && let mbe::TokenTree::Delimited(.., del) = args && del.delim != Delimiter::Invisible { true @@ -778,7 +779,7 @@ impl<'tt> FirstSets<'tt> { | TokenTree::MetaVarExpr(..) => { first.replace_with(TtHandle::TtRef(tt)); } - TokenTree::Delimited(span, delimited) => { + TokenTree::Delimited(span, _, delimited) => { build_recur(sets, &delimited.tts); first.replace_with(TtHandle::from_token_kind( token::OpenDelim(delimited.delim), @@ -847,7 +848,7 @@ impl<'tt> FirstSets<'tt> { first.add_one(TtHandle::TtRef(tt)); return first; } - TokenTree::Delimited(span, delimited) => { + TokenTree::Delimited(span, _, delimited) => { first.add_one(TtHandle::from_token_kind( token::OpenDelim(delimited.delim), span.open, @@ -927,7 +928,7 @@ impl<'tt> TtHandle<'tt> { fn get(&'tt self) -> &'tt mbe::TokenTree { match self { TtHandle::TtRef(tt) => tt, - TtHandle::Token(token_tt) => &token_tt, + TtHandle::Token(token_tt) => token_tt, } } } @@ -1092,7 +1093,7 @@ fn check_matcher_core<'tt>( suffix_first = build_suffix_first(); } } - TokenTree::Delimited(span, d) => { + TokenTree::Delimited(span, _, d) => { let my_suffix = TokenSet::singleton(TtHandle::from_token_kind( token::CloseDelim(d.delim), span.close, @@ -1170,7 +1171,7 @@ fn check_matcher_core<'tt>( Some(NonterminalKind::PatParam { inferred: false }), )); sess.buffer_lint_with_diagnostic( - &RUST_2021_INCOMPATIBLE_OR_PATTERNS, + RUST_2021_INCOMPATIBLE_OR_PATTERNS, span, ast::CRATE_NODE_ID, "the meaning of the `pat` fragment specifier is changing in Rust 2021, which may affect this macro", @@ -1188,7 +1189,7 @@ fn check_matcher_core<'tt>( }; let sp = next_token.span(); - let mut err = sess.span_diagnostic.struct_span_err( + let mut err = sess.dcx.struct_span_err( sp, format!( "`${name}:{frag}` {may_be} followed by `{next}`, which \ @@ -1407,7 +1408,7 @@ fn is_in_follow(tok: &mbe::TokenTree, kind: NonterminalKind) -> IsInFollow { fn quoted_tt_to_string(tt: &mbe::TokenTree) -> String { match tt { - mbe::TokenTree::Token(token) => pprust::token_to_string(&token).into(), + mbe::TokenTree::Token(token) => pprust::token_to_string(token).into(), mbe::TokenTree::MetaVar(_, name) => format!("${name}"), mbe::TokenTree::MetaVarDecl(_, name, Some(kind)) => format!("${name}:{kind}"), mbe::TokenTree::MetaVarDecl(_, name, None) => format!("${name}:"), diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs index 7cb279a98..e3dc73d0d 100644 --- a/compiler/rustc_expand/src/mbe/metavar_expr.rs +++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs @@ -10,9 +10,8 @@ use rustc_span::Span; /// A meta-variable expression, for expansions based on properties of meta-variables. #[derive(Debug, Clone, PartialEq, Encodable, Decodable)] pub(crate) enum MetaVarExpr { - /// The number of repetitions of an identifier, optionally limited to a number - /// of outer-most repetition depths. If the depth limit is `None` then the depth is unlimited. - Count(Ident, Option<usize>), + /// The number of repetitions of an identifier. + Count(Ident, usize), /// Ignore a meta-variable for repetition without expansion. Ignore(Ident), @@ -35,20 +34,23 @@ impl MetaVarExpr { ) -> PResult<'sess, MetaVarExpr> { let mut tts = input.trees(); let ident = parse_ident(&mut tts, sess, outer_span)?; - let Some(TokenTree::Delimited(_, Delimiter::Parenthesis, args)) = tts.next() else { + let Some(TokenTree::Delimited(.., Delimiter::Parenthesis, args)) = tts.next() else { let msg = "meta-variable expression parameter must be wrapped in parentheses"; - return Err(sess.span_diagnostic.struct_span_err(ident.span, msg)); + return Err(sess.dcx.struct_span_err(ident.span, msg)); }; check_trailing_token(&mut tts, sess)?; let mut iter = args.trees(); let rslt = match ident.as_str() { "count" => parse_count(&mut iter, sess, ident.span)?, - "ignore" => MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?), + "ignore" => { + eat_dollar(&mut iter, sess, ident.span)?; + MetaVarExpr::Ignore(parse_ident(&mut iter, sess, ident.span)?) + } "index" => MetaVarExpr::Index(parse_depth(&mut iter, sess, ident.span)?), "length" => MetaVarExpr::Length(parse_depth(&mut iter, sess, ident.span)?), _ => { let err_msg = "unrecognized meta-variable expression"; - let mut err = sess.span_diagnostic.struct_span_err(ident.span, err_msg); + let mut err = sess.dcx.struct_span_err(ident.span, err_msg); err.span_suggestion( ident.span, "supported expressions are count, ignore, index and length", @@ -77,7 +79,7 @@ fn check_trailing_token<'sess>( ) -> PResult<'sess, ()> { if let Some(tt) = iter.next() { let mut diag = sess - .span_diagnostic + .dcx .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt))); diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens"); Err(diag) @@ -92,17 +94,18 @@ fn parse_count<'sess>( sess: &'sess ParseSess, span: Span, ) -> PResult<'sess, MetaVarExpr> { + eat_dollar(iter, sess, span)?; let ident = parse_ident(iter, sess, span)?; let depth = if try_eat_comma(iter) { if iter.look_ahead(0).is_none() { - return Err(sess.span_diagnostic.struct_span_err( + return Err(sess.dcx.struct_span_err( span, "`count` followed by a comma must have an associated index indicating its depth", )); } - Some(parse_depth(iter, sess, span)?) + parse_depth(iter, sess, span)? } else { - None + 0 }; Ok(MetaVarExpr::Count(ident, depth)) } @@ -116,7 +119,7 @@ fn parse_depth<'sess>( let Some(tt) = iter.next() else { return Ok(0) }; let TokenTree::Token(token::Token { kind: token::TokenKind::Literal(lit), .. }, _) = tt else { return Err(sess - .span_diagnostic + .dcx .struct_span_err(span, "meta-variable expression depth must be a literal")); }; if let Ok(lit_kind) = LitKind::from_token_lit(*lit) @@ -126,7 +129,7 @@ fn parse_depth<'sess>( Ok(n_usize) } else { let msg = "only unsuffixes integer literals are supported in meta-variable expressions"; - Err(sess.span_diagnostic.struct_span_err(span, msg)) + Err(sess.dcx.struct_span_err(span, msg)) } } @@ -143,9 +146,8 @@ fn parse_ident<'sess>( return Ok(elem); } let token_str = pprust::token_to_string(token); - let mut err = sess - .span_diagnostic - .struct_span_err(span, format!("expected identifier, found `{}`", &token_str)); + let mut err = + sess.dcx.struct_span_err(span, format!("expected identifier, found `{}`", &token_str)); err.span_suggestion( token.span, format!("try removing `{}`", &token_str), @@ -154,7 +156,7 @@ fn parse_ident<'sess>( ); return Err(err); } - Err(sess.span_diagnostic.struct_span_err(span, "expected identifier")) + Err(sess.dcx.struct_span_err(span, "expected identifier")) } /// Tries to move the iterator forward returning `true` if there is a comma. If not, then the @@ -166,3 +168,20 @@ fn try_eat_comma(iter: &mut RefTokenTreeCursor<'_>) -> bool { } false } + +/// Expects that the next item is a dollar sign. +fn eat_dollar<'sess>( + iter: &mut RefTokenTreeCursor<'_>, + sess: &'sess ParseSess, + span: Span, +) -> PResult<'sess, ()> { + if let Some(TokenTree::Token(token::Token { kind: token::Dollar, .. }, _)) = iter.look_ahead(0) + { + let _ = iter.next(); + return Ok(()); + } + Err(sess.dcx.struct_span_err( + span, + "meta-variables within meta-variable expressions must be referenced using a dollar sign", + )) +} diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs index 6546199f5..445be01bc 100644 --- a/compiler/rustc_expand/src/mbe/quoted.rs +++ b/compiler/rustc_expand/src/mbe/quoted.rs @@ -84,7 +84,7 @@ pub(super) fn parse( "invalid fragment specifier `{}`", frag.name ); - sess.span_diagnostic + sess.dcx .struct_span_err(span, msg) .help(VALID_FRAGMENT_NAMES_MSG) .emit(); @@ -116,7 +116,7 @@ pub(super) fn parse( fn maybe_emit_macro_metavar_expr_feature(features: &Features, sess: &ParseSess, span: Span) { if !features.macro_metavar_expr { let msg = "meta-variable expressions are unstable"; - feature_err(&sess, sym::macro_metavar_expr, span, msg).emit(); + feature_err(sess, sym::macro_metavar_expr, span, msg).emit(); } } @@ -151,7 +151,7 @@ fn parse_tree<'a>( // during parsing. let mut next = outer_trees.next(); let mut trees: Box<dyn Iterator<Item = &tokenstream::TokenTree>>; - if let Some(tokenstream::TokenTree::Delimited(_, Delimiter::Invisible, tts)) = next { + if let Some(tokenstream::TokenTree::Delimited(.., Delimiter::Invisible, tts)) = next { trees = Box::new(tts.trees()); next = trees.next(); } else { @@ -160,7 +160,7 @@ fn parse_tree<'a>( match next { // `tree` is followed by a delimited set of token trees. - Some(&tokenstream::TokenTree::Delimited(delim_span, delim, ref tts)) => { + Some(&tokenstream::TokenTree::Delimited(delim_span, _, delim, ref tts)) => { if parsing_patterns { if delim != Delimiter::Parenthesis { span_dollar_dollar_or_metavar_in_the_lhs_err( @@ -174,7 +174,7 @@ fn parse_tree<'a>( // The delimiter is `{`. This indicates the beginning // of a meta-variable expression (e.g. `${count(ident)}`). // Try to parse the meta-variable expression. - match MetaVarExpr::parse(&tts, delim_span.entire(), sess) { + match MetaVarExpr::parse(tts, delim_span.entire(), sess) { Err(mut err) => { err.emit(); // Returns early the same read `$` to avoid spanning @@ -195,7 +195,7 @@ fn parse_tree<'a>( _ => { let tok = pprust::token_kind_to_string(&token::OpenDelim(delim)); let msg = format!("expected `(` or `{{`, found `{tok}`"); - sess.span_diagnostic.span_err(delim_span.entire(), msg); + sess.dcx.span_err(delim_span.entire(), msg); } } } @@ -242,11 +242,9 @@ fn parse_tree<'a>( // `tree` is followed by some other token. This is an error. Some(tokenstream::TokenTree::Token(token, _)) => { - let msg = format!( - "expected identifier, found `{}`", - pprust::token_to_string(&token), - ); - sess.span_diagnostic.span_err(token.span, msg); + let msg = + format!("expected identifier, found `{}`", pprust::token_to_string(token),); + sess.dcx.span_err(token.span, msg); TokenTree::MetaVar(token.span, Ident::empty()) } @@ -260,8 +258,9 @@ fn parse_tree<'a>( // `tree` is the beginning of a delimited set of tokens (e.g., `(` or `{`). We need to // descend into the delimited set and further parse it. - &tokenstream::TokenTree::Delimited(span, delim, ref tts) => TokenTree::Delimited( + &tokenstream::TokenTree::Delimited(span, spacing, delim, ref tts) => TokenTree::Delimited( span, + spacing, Delimited { delim, tts: parse(tts, parsing_patterns, sess, node_id, features, edition), @@ -291,7 +290,7 @@ fn parse_kleene_op<'a>( span: Span, ) -> Result<Result<(KleeneOp, Span), Token>, Span> { match input.next() { - Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(&token) { + Some(tokenstream::TokenTree::Token(token, _)) => match kleene_op(token) { Some(op) => Ok(Ok((op, token.span))), None => Ok(Err(token.clone())), }, @@ -326,7 +325,7 @@ fn parse_sep_and_kleene_op<'a>( // #2 is the `?` Kleene op, which does not take a separator (error) Ok(Ok((KleeneOp::ZeroOrOne, span))) => { // Error! - sess.span_diagnostic.span_err( + sess.dcx.span_err( token.span, "the `?` macro repetition operator does not take a separator", ); @@ -347,7 +346,7 @@ fn parse_sep_and_kleene_op<'a>( }; // If we ever get to this point, we have experienced an "unexpected token" error - sess.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`"); + sess.dcx.span_err(span, "expected one of: `*`, `+`, or `?`"); // Return a dummy (None, KleeneToken::new(KleeneOp::ZeroOrMore, span)) @@ -357,9 +356,8 @@ fn parse_sep_and_kleene_op<'a>( // // For example, `macro_rules! foo { ( ${length()} ) => {} }` fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) { - sess.span_diagnostic - .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token))); - sess.span_diagnostic.span_note_without_error( + sess.dcx.span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token))); + sess.dcx.span_note( token.span, "`$$` and meta-variable expressions are not allowed inside macro parameter definitions", ); 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(), |