Run rustfmt
This commit is contained in:
parent
a96ba96915
commit
0aeab41e5a
@ -1,37 +1,37 @@
|
||||
use crate::{ast, attr};
|
||||
use crate::edition::Edition;
|
||||
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use crate::ext::base::{DummyResult, ExtCtxt, MacResult, TTMacroExpander};
|
||||
use crate::ext::base::{SyntaxExtension, SyntaxExtensionKind};
|
||||
use crate::ext::expand::{AstFragment, AstFragmentKind};
|
||||
use crate::ext::hygiene::Transparency;
|
||||
use crate::ext::tt::macro_parser::{Success, Error, Failure};
|
||||
use crate::ext::tt::macro_parser::{MatchedSeq, MatchedNonterminal};
|
||||
use crate::ext::tt::macro_parser::{parse, parse_failure_msg};
|
||||
use crate::ext::tt::macro_parser::{Error, Failure, Success};
|
||||
use crate::ext::tt::macro_parser::{MatchedNonterminal, MatchedSeq};
|
||||
use crate::ext::tt::quoted;
|
||||
use crate::ext::tt::transcribe::transcribe;
|
||||
use crate::feature_gate::Features;
|
||||
use crate::parse::{Directory, ParseSess};
|
||||
use crate::parse::parser::Parser;
|
||||
use crate::parse::token::{self, Token, NtTT};
|
||||
use crate::parse::token::TokenKind::*;
|
||||
use crate::symbol::{Symbol, kw, sym};
|
||||
use crate::parse::token::{self, NtTT, Token};
|
||||
use crate::parse::{Directory, ParseSess};
|
||||
use crate::symbol::{kw, sym, Symbol};
|
||||
use crate::tokenstream::{DelimSpan, TokenStream, TokenTree};
|
||||
use crate::{ast, attr};
|
||||
|
||||
use errors::FatalError;
|
||||
use syntax_pos::{Span, symbol::Ident};
|
||||
use log::debug;
|
||||
use syntax_pos::{symbol::Ident, Span};
|
||||
|
||||
use rustc_data_structures::fx::{FxHashMap};
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::slice;
|
||||
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
use errors::Applicability;
|
||||
use rustc_data_structures::sync::Lrc;
|
||||
|
||||
const VALID_FRAGMENT_NAMES_MSG: &str = "valid fragment specifiers are \
|
||||
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, `literal`, \
|
||||
`path`, `meta`, `tt`, `item` and `vis`";
|
||||
`ident`, `block`, `stmt`, `expr`, `pat`, `ty`, `lifetime`, \
|
||||
`literal`, `path`, `meta`, `tt`, `item` and `vis`";
|
||||
|
||||
pub struct ParserAnyMacro<'a> {
|
||||
parser: Parser<'a>,
|
||||
@ -48,7 +48,8 @@ pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFrag
|
||||
let ParserAnyMacro { site_span, macro_ident, ref mut parser, arm_span } = *self;
|
||||
let fragment = panictry!(parser.parse_ast_fragment(kind, true).map_err(|mut e| {
|
||||
if parser.token == token::Eof && e.message().ends_with(", found `<eof>`") {
|
||||
if !e.span.is_dummy() { // early end of macro arm (#52866)
|
||||
if !e.span.is_dummy() {
|
||||
// early end of macro arm (#52866)
|
||||
e.replace_span_with(parser.sess.source_map().next_point(parser.token.span));
|
||||
}
|
||||
let msg = &e.message[0];
|
||||
@ -60,7 +61,8 @@ pub fn make(mut self: Box<ParserAnyMacro<'a>>, kind: AstFragmentKind) -> AstFrag
|
||||
msg.1,
|
||||
);
|
||||
}
|
||||
if e.span.is_dummy() { // Get around lack of span in error (#30128)
|
||||
if e.span.is_dummy() {
|
||||
// Get around lack of span in error (#30128)
|
||||
e.replace_span_with(site_span);
|
||||
if parser.sess.source_map().span_to_filename(arm_span).is_real() {
|
||||
e.span_label(arm_span, "in this macro arm");
|
||||
@ -99,17 +101,11 @@ fn expand<'cx>(
|
||||
sp: Span,
|
||||
input: TokenStream,
|
||||
def_span: Option<Span>,
|
||||
) -> Box<dyn MacResult+'cx> {
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
if !self.valid {
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
generic_extension(cx,
|
||||
sp,
|
||||
def_span,
|
||||
self.name,
|
||||
input,
|
||||
&self.lhses,
|
||||
&self.rhses)
|
||||
generic_extension(cx, sp, def_span, self.name, input, &self.lhses, &self.rhses)
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,14 +115,15 @@ fn trace_macros_note(cx: &mut ExtCtxt<'_>, sp: Span, message: String) {
|
||||
}
|
||||
|
||||
/// Given `lhses` and `rhses`, this is the new macro we create
|
||||
fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
def_span: Option<Span>,
|
||||
name: ast::Ident,
|
||||
arg: TokenStream,
|
||||
lhses: &[quoted::TokenTree],
|
||||
rhses: &[quoted::TokenTree])
|
||||
-> Box<dyn MacResult+'cx> {
|
||||
fn generic_extension<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
def_span: Option<Span>,
|
||||
name: ast::Ident,
|
||||
arg: TokenStream,
|
||||
lhses: &[quoted::TokenTree],
|
||||
rhses: &[quoted::TokenTree],
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
if cx.trace_macros() {
|
||||
trace_macros_note(cx, sp, format!("expanding `{}! {{ {} }}`", name, arg));
|
||||
}
|
||||
@ -134,10 +131,11 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
||||
// Which arm's failure should we report? (the one furthest along)
|
||||
let mut best_failure: Option<(Token, &str)> = None;
|
||||
|
||||
for (i, lhs) in lhses.iter().enumerate() { // try each arm's matchers
|
||||
for (i, lhs) in lhses.iter().enumerate() {
|
||||
// try each arm's matchers
|
||||
let lhs_tt = match *lhs {
|
||||
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
||||
_ => cx.span_bug(sp, "malformed macro lhs")
|
||||
_ => cx.span_bug(sp, "malformed macro lhs"),
|
||||
};
|
||||
|
||||
match TokenTree::parse(cx, lhs_tt, arg.clone()) {
|
||||
@ -173,8 +171,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
||||
ownership: cx.current_expansion.directory_ownership,
|
||||
};
|
||||
let mut p = Parser::new(cx.parse_sess(), tts, Some(directory), true, false, None);
|
||||
p.root_module_name = cx.current_expansion.module.mod_path.last()
|
||||
.map(|id| id.as_str().to_string());
|
||||
p.root_module_name =
|
||||
cx.current_expansion.module.mod_path.last().map(|id| id.as_str().to_string());
|
||||
|
||||
p.process_potential_macro_variable();
|
||||
// Let the context choose how to interpret the result.
|
||||
@ -188,15 +186,13 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
||||
site_span: sp,
|
||||
macro_ident: name,
|
||||
arm_span,
|
||||
})
|
||||
});
|
||||
}
|
||||
Failure(token, msg) => match best_failure {
|
||||
Some((ref best_token, _)) if best_token.span.lo() >= token.span.lo() => {}
|
||||
_ => best_failure = Some((token, msg))
|
||||
}
|
||||
Error(err_sp, ref msg) => {
|
||||
cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..])
|
||||
}
|
||||
_ => best_failure = Some((token, msg)),
|
||||
},
|
||||
Error(err_sp, ref msg) => cx.span_fatal(err_sp.substitute_dummy(sp), &msg[..]),
|
||||
}
|
||||
}
|
||||
|
||||
@ -212,7 +208,8 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt<'_>,
|
||||
|
||||
// Check whether there's a missing comma in this macro call, like `println!("{}" a);`
|
||||
if let Some((arg, comma_span)) = arg.add_comma() {
|
||||
for lhs in lhses { // try each arm's matchers
|
||||
for lhs in lhses {
|
||||
// try each arm's matchers
|
||||
let lhs_tt = match *lhs {
|
||||
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
||||
_ => continue,
|
||||
@ -249,7 +246,7 @@ pub fn compile(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
def: &ast::Item,
|
||||
edition: Edition
|
||||
edition: Edition,
|
||||
) -> SyntaxExtension {
|
||||
let lhs_nm = ast::Ident::new(sym::lhs, def.span);
|
||||
let rhs_nm = ast::Ident::new(sym::rhs, def.span);
|
||||
@ -267,25 +264,32 @@ pub fn compile(
|
||||
// ...quasiquoting this would be nice.
|
||||
// These spans won't matter, anyways
|
||||
let argument_gram = vec![
|
||||
quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition {
|
||||
tts: vec![
|
||||
quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
|
||||
quoted::TokenTree::token(token::FatArrow, def.span),
|
||||
quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
|
||||
],
|
||||
separator: Some(Token::new(
|
||||
if body.legacy { token::Semi } else { token::Comma }, def.span
|
||||
)),
|
||||
op: quoted::KleeneOp::OneOrMore,
|
||||
num_captures: 2,
|
||||
})),
|
||||
quoted::TokenTree::Sequence(
|
||||
DelimSpan::dummy(),
|
||||
Lrc::new(quoted::SequenceRepetition {
|
||||
tts: vec![
|
||||
quoted::TokenTree::MetaVarDecl(def.span, lhs_nm, tt_spec),
|
||||
quoted::TokenTree::token(token::FatArrow, def.span),
|
||||
quoted::TokenTree::MetaVarDecl(def.span, rhs_nm, tt_spec),
|
||||
],
|
||||
separator: Some(Token::new(
|
||||
if body.legacy { token::Semi } else { token::Comma },
|
||||
def.span,
|
||||
)),
|
||||
op: quoted::KleeneOp::OneOrMore,
|
||||
num_captures: 2,
|
||||
}),
|
||||
),
|
||||
// to phase into semicolon-termination instead of semicolon-separation
|
||||
quoted::TokenTree::Sequence(DelimSpan::dummy(), Lrc::new(quoted::SequenceRepetition {
|
||||
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
|
||||
separator: None,
|
||||
op: quoted::KleeneOp::ZeroOrMore,
|
||||
num_captures: 0
|
||||
})),
|
||||
quoted::TokenTree::Sequence(
|
||||
DelimSpan::dummy(),
|
||||
Lrc::new(quoted::SequenceRepetition {
|
||||
tts: vec![quoted::TokenTree::token(token::Semi, def.span)],
|
||||
separator: None,
|
||||
op: quoted::KleeneOp::ZeroOrMore,
|
||||
num_captures: 0,
|
||||
}),
|
||||
),
|
||||
];
|
||||
|
||||
let argument_map = match parse(sess, body.stream(), &argument_gram, None, true) {
|
||||
@ -307,8 +311,9 @@ pub fn compile(
|
||||
|
||||
// Extract the arguments:
|
||||
let lhses = match *argument_map[&lhs_nm] {
|
||||
MatchedSeq(ref s, _) => {
|
||||
s.iter().map(|m| {
|
||||
MatchedSeq(ref s, _) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
if let MatchedNonterminal(ref nt) = *m {
|
||||
if let NtTT(ref tt) = **nt {
|
||||
let tt = quoted::parse(
|
||||
@ -327,14 +332,15 @@ pub fn compile(
|
||||
}
|
||||
}
|
||||
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
|
||||
}).collect::<Vec<quoted::TokenTree>>()
|
||||
}
|
||||
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
|
||||
})
|
||||
.collect::<Vec<quoted::TokenTree>>(),
|
||||
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs"),
|
||||
};
|
||||
|
||||
let rhses = match *argument_map[&rhs_nm] {
|
||||
MatchedSeq(ref s, _) => {
|
||||
s.iter().map(|m| {
|
||||
MatchedSeq(ref s, _) => s
|
||||
.iter()
|
||||
.map(|m| {
|
||||
if let MatchedNonterminal(ref nt) = *m {
|
||||
if let NtTT(ref tt) = **nt {
|
||||
return quoted::parse(
|
||||
@ -345,14 +351,15 @@ pub fn compile(
|
||||
&def.attrs,
|
||||
edition,
|
||||
def.id,
|
||||
).pop()
|
||||
.unwrap();
|
||||
)
|
||||
.pop()
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
sess.span_diagnostic.span_bug(def.span, "wrong-structured lhs")
|
||||
}).collect::<Vec<quoted::TokenTree>>()
|
||||
}
|
||||
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs")
|
||||
})
|
||||
.collect::<Vec<quoted::TokenTree>>(),
|
||||
_ => sess.span_diagnostic.span_bug(def.span, "wrong-structured rhs"),
|
||||
};
|
||||
|
||||
for rhs in &rhses {
|
||||
@ -366,16 +373,12 @@ pub fn compile(
|
||||
sess,
|
||||
slice::from_ref(lhs),
|
||||
&mut FxHashMap::default(),
|
||||
def.id
|
||||
def.id,
|
||||
);
|
||||
}
|
||||
|
||||
let expander: Box<_> = Box::new(MacroRulesMacroExpander {
|
||||
name: def.ident,
|
||||
lhses,
|
||||
rhses,
|
||||
valid,
|
||||
});
|
||||
let expander: Box<_> =
|
||||
Box::new(MacroRulesMacroExpander { name: def.ident, lhses, rhses, valid });
|
||||
|
||||
let default_transparency = if attr::contains_name(&def.attrs, sym::rustc_transparent_macro) {
|
||||
Transparency::Transparent
|
||||
@ -385,29 +388,34 @@ pub fn compile(
|
||||
Transparency::Opaque
|
||||
};
|
||||
|
||||
let allow_internal_unstable = attr::find_by_name(&def.attrs, sym::allow_internal_unstable)
|
||||
.map(|attr| attr
|
||||
.meta_item_list()
|
||||
.map(|list| list.iter()
|
||||
.filter_map(|it| {
|
||||
let name = it.ident().map(|ident| ident.name);
|
||||
if name.is_none() {
|
||||
sess.span_diagnostic.span_err(it.span(),
|
||||
"allow internal unstable expects feature names")
|
||||
}
|
||||
name
|
||||
let allow_internal_unstable =
|
||||
attr::find_by_name(&def.attrs, sym::allow_internal_unstable).map(|attr| {
|
||||
attr.meta_item_list()
|
||||
.map(|list| {
|
||||
list.iter()
|
||||
.filter_map(|it| {
|
||||
let name = it.ident().map(|ident| ident.name);
|
||||
if name.is_none() {
|
||||
sess.span_diagnostic.span_err(
|
||||
it.span(),
|
||||
"allow internal unstable expects feature names",
|
||||
)
|
||||
}
|
||||
name
|
||||
})
|
||||
.collect::<Vec<Symbol>>()
|
||||
.into()
|
||||
})
|
||||
.collect::<Vec<Symbol>>().into()
|
||||
)
|
||||
.unwrap_or_else(|| {
|
||||
sess.span_diagnostic.span_warn(
|
||||
attr.span, "allow_internal_unstable expects list of feature names. In the \
|
||||
future this will become a hard error. Please use `allow_internal_unstable(\
|
||||
foo, bar)` to only allow the `foo` and `bar` features",
|
||||
);
|
||||
vec![sym::allow_internal_unstable_backcompat_hack].into()
|
||||
})
|
||||
);
|
||||
.unwrap_or_else(|| {
|
||||
sess.span_diagnostic.span_warn(
|
||||
attr.span,
|
||||
"allow_internal_unstable expects list of feature names. In the \
|
||||
future this will become a hard error. Please use `allow_internal_unstable(\
|
||||
foo, bar)` to only allow the `foo` and `bar` features",
|
||||
);
|
||||
vec![sym::allow_internal_unstable_backcompat_hack].into()
|
||||
})
|
||||
});
|
||||
|
||||
let allow_internal_unsafe = attr::contains_name(&def.attrs, sym::allow_internal_unsafe);
|
||||
|
||||
@ -418,14 +426,14 @@ pub fn compile(
|
||||
}
|
||||
}
|
||||
|
||||
let unstable_feature = attr::find_stability(&sess,
|
||||
&def.attrs, def.span).and_then(|stability| {
|
||||
if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
|
||||
Some((stability.feature, issue))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let unstable_feature =
|
||||
attr::find_stability(&sess, &def.attrs, def.span).and_then(|stability| {
|
||||
if let attr::StabilityLevel::Unstable { issue, .. } = stability.level {
|
||||
Some((stability.feature, issue))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
SyntaxExtension {
|
||||
kind: SyntaxExtensionKind::LegacyBang(expander),
|
||||
@ -440,10 +448,12 @@ pub fn compile(
|
||||
}
|
||||
}
|
||||
|
||||
fn check_lhs_nt_follows(sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
lhs: "ed::TokenTree) -> bool {
|
||||
fn check_lhs_nt_follows(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
lhs: "ed::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 quoted::TokenTree::Delimited(_, ref tts) = *lhs {
|
||||
@ -464,19 +474,22 @@ fn check_lhs_no_empty_seq(sess: &ParseSess, tts: &[quoted::TokenTree]) -> bool {
|
||||
for tt in tts {
|
||||
match *tt {
|
||||
TokenTree::Token(..) | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) => (),
|
||||
TokenTree::Delimited(_, ref del) => if !check_lhs_no_empty_seq(sess, &del.tts) {
|
||||
return false;
|
||||
},
|
||||
TokenTree::Delimited(_, ref del) => {
|
||||
if !check_lhs_no_empty_seq(sess, &del.tts) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
TokenTree::Sequence(span, ref seq) => {
|
||||
if seq.separator.is_none() && seq.tts.iter().all(|seq_tt| {
|
||||
match *seq_tt {
|
||||
if seq.separator.is_none()
|
||||
&& seq.tts.iter().all(|seq_tt| match *seq_tt {
|
||||
TokenTree::MetaVarDecl(_, _, id) => id.name == sym::vis,
|
||||
TokenTree::Sequence(_, ref sub_seq) =>
|
||||
TokenTree::Sequence(_, ref sub_seq) => {
|
||||
sub_seq.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne,
|
||||
|| sub_seq.op == quoted::KleeneOp::ZeroOrOne
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}) {
|
||||
})
|
||||
{
|
||||
let sp = span.entire();
|
||||
sess.span_diagnostic.span_err(sp, "repetition matches empty token tree");
|
||||
return false;
|
||||
@ -517,7 +530,7 @@ fn check_lhs_duplicate_matcher_bindings(
|
||||
if !check_lhs_duplicate_matcher_bindings(sess, &del.tts, metavar_names, node_id) {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
}
|
||||
TokenTree::Sequence(_, ref seq) => {
|
||||
if !check_lhs_duplicate_matcher_bindings(sess, &seq.tts, metavar_names, node_id) {
|
||||
return false;
|
||||
@ -533,15 +546,17 @@ fn check_lhs_duplicate_matcher_bindings(
|
||||
fn check_rhs(sess: &ParseSess, rhs: "ed::TokenTree) -> bool {
|
||||
match *rhs {
|
||||
quoted::TokenTree::Delimited(..) => return true,
|
||||
_ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited")
|
||||
_ => sess.span_diagnostic.span_err(rhs.span(), "macro rhs must be delimited"),
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
fn check_matcher(sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
matcher: &[quoted::TokenTree]) -> bool {
|
||||
fn check_matcher(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
matcher: &[quoted::TokenTree],
|
||||
) -> bool {
|
||||
let first_sets = FirstSets::new(matcher);
|
||||
let empty_suffix = TokenSet::empty();
|
||||
let err = sess.span_diagnostic.err_count();
|
||||
@ -620,8 +635,8 @@ fn build_recur(sets: &mut FirstSets, tts: &[TokenTree]) -> TokenSet {
|
||||
|
||||
// Reverse scan: Sequence comes before `first`.
|
||||
if subfirst.maybe_empty
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
||||
{
|
||||
// If sequence is potentially empty, then
|
||||
// union them (preserving first emptiness).
|
||||
@ -659,7 +674,6 @@ fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet {
|
||||
TokenTree::Sequence(sp, ref seq_rep) => {
|
||||
match self.first.get(&sp.entire()) {
|
||||
Some(&Some(ref subfirst)) => {
|
||||
|
||||
// If the sequence contents can be empty, then the first
|
||||
// token could be the separator token itself.
|
||||
|
||||
@ -670,8 +684,8 @@ fn first(&self, tts: &[quoted::TokenTree]) -> TokenSet {
|
||||
assert!(first.maybe_empty);
|
||||
first.add_all(subfirst);
|
||||
if subfirst.maybe_empty
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrMore
|
||||
|| seq_rep.op == quoted::KleeneOp::ZeroOrOne
|
||||
{
|
||||
// continue scanning for more first
|
||||
// tokens, but also make sure we
|
||||
@ -720,7 +734,9 @@ struct TokenSet {
|
||||
|
||||
impl TokenSet {
|
||||
// Returns a set for the empty sequence.
|
||||
fn empty() -> Self { TokenSet { tokens: Vec::new(), maybe_empty: true } }
|
||||
fn empty() -> Self {
|
||||
TokenSet { tokens: Vec::new(), maybe_empty: true }
|
||||
}
|
||||
|
||||
// Returns the set `{ tok }` for the single-token (and thus
|
||||
// non-empty) sequence [tok].
|
||||
@ -789,12 +805,14 @@ fn add_all(&mut self, other: &Self) {
|
||||
//
|
||||
// Requires that `first_sets` is pre-computed for `matcher`;
|
||||
// see `FirstSets::new`.
|
||||
fn check_matcher_core(sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
first_sets: &FirstSets,
|
||||
matcher: &[quoted::TokenTree],
|
||||
follow: &TokenSet) -> TokenSet {
|
||||
fn check_matcher_core(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
first_sets: &FirstSets,
|
||||
matcher: &[quoted::TokenTree],
|
||||
follow: &TokenSet,
|
||||
) -> TokenSet {
|
||||
use quoted::TokenTree;
|
||||
|
||||
let mut last = TokenSet::empty();
|
||||
@ -804,11 +822,13 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
// then ensure T can also be followed by any element of FOLLOW.
|
||||
'each_token: for i in 0..matcher.len() {
|
||||
let token = &matcher[i];
|
||||
let suffix = &matcher[i+1..];
|
||||
let suffix = &matcher[i + 1..];
|
||||
|
||||
let build_suffix_first = || {
|
||||
let mut s = first_sets.first(suffix);
|
||||
if s.maybe_empty { s.add_all(follow); }
|
||||
if s.maybe_empty {
|
||||
s.add_all(follow);
|
||||
}
|
||||
s
|
||||
};
|
||||
|
||||
@ -824,7 +844,8 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
let can_be_followed_by_any;
|
||||
if let Err(bad_frag) = has_legal_fragment_specifier(sess, features, attrs, token) {
|
||||
let msg = format!("invalid fragment specifier `{}`", bad_frag);
|
||||
sess.span_diagnostic.struct_span_err(token.span(), &msg)
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(token.span(), &msg)
|
||||
.help(VALID_FRAGMENT_NAMES_MSG)
|
||||
.emit();
|
||||
// (This eliminates false positives and duplicates
|
||||
@ -879,12 +900,8 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
// At this point, `suffix_first` is built, and
|
||||
// `my_suffix` is some TokenSet that we can use
|
||||
// for checking the interior of `seq_rep`.
|
||||
let next = check_matcher_core(sess,
|
||||
features,
|
||||
attrs,
|
||||
first_sets,
|
||||
&seq_rep.tts,
|
||||
my_suffix);
|
||||
let next =
|
||||
check_matcher_core(sess, features, attrs, first_sets, &seq_rep.tts, my_suffix);
|
||||
if next.maybe_empty {
|
||||
last.add_all(&next);
|
||||
} else {
|
||||
@ -906,16 +923,17 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
for next_token in &suffix_first.tokens {
|
||||
match is_in_follow(next_token, &frag_spec.as_str()) {
|
||||
IsInFollow::Invalid(msg, help) => {
|
||||
sess.span_diagnostic.struct_span_err(next_token.span(), &msg)
|
||||
.help(help).emit();
|
||||
sess.span_diagnostic
|
||||
.struct_span_err(next_token.span(), &msg)
|
||||
.help(help)
|
||||
.emit();
|
||||
// don't bother reporting every source of
|
||||
// conflict for a particular element of `last`.
|
||||
continue 'each_last;
|
||||
}
|
||||
IsInFollow::Yes => {}
|
||||
IsInFollow::No(possible) => {
|
||||
let may_be = if last.tokens.len() == 1 &&
|
||||
suffix_first.tokens.len() == 1
|
||||
let may_be = if last.tokens.len() == 1 && suffix_first.tokens.len() == 1
|
||||
{
|
||||
"is"
|
||||
} else {
|
||||
@ -925,12 +943,14 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
let sp = next_token.span();
|
||||
let mut err = sess.span_diagnostic.struct_span_err(
|
||||
sp,
|
||||
&format!("`${name}:{frag}` {may_be} followed by `{next}`, which \
|
||||
is not allowed for `{frag}` fragments",
|
||||
name=name,
|
||||
frag=frag_spec,
|
||||
next=quoted_tt_to_string(next_token),
|
||||
may_be=may_be),
|
||||
&format!(
|
||||
"`${name}:{frag}` {may_be} followed by `{next}`, which \
|
||||
is not allowed for `{frag}` fragments",
|
||||
name = name,
|
||||
frag = frag_spec,
|
||||
next = quoted_tt_to_string(next_token),
|
||||
may_be = may_be
|
||||
),
|
||||
);
|
||||
err.span_label(
|
||||
sp,
|
||||
@ -942,16 +962,18 @@ fn check_matcher_core(sess: &ParseSess,
|
||||
&[t] => {
|
||||
err.note(&format!(
|
||||
"only {} is allowed after `{}` fragments",
|
||||
t,
|
||||
frag_spec,
|
||||
t, frag_spec,
|
||||
));
|
||||
}
|
||||
ts => {
|
||||
err.note(&format!(
|
||||
"{}{} or {}",
|
||||
msg,
|
||||
ts[..ts.len() - 1].iter().map(|s| *s)
|
||||
.collect::<Vec<_>>().join(", "),
|
||||
ts[..ts.len() - 1]
|
||||
.iter()
|
||||
.map(|s| *s)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
ts[ts.len() - 1],
|
||||
));
|
||||
}
|
||||
@ -1026,13 +1048,13 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow {
|
||||
// since items *must* be followed by either a `;` or a `}`, we can
|
||||
// accept anything after them
|
||||
IsInFollow::Yes
|
||||
},
|
||||
}
|
||||
"block" => {
|
||||
// anything can follow block, the braces provide an easy boundary to
|
||||
// maintain
|
||||
IsInFollow::Yes
|
||||
},
|
||||
"stmt" | "expr" => {
|
||||
}
|
||||
"stmt" | "expr" => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`;`"];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
@ -1041,7 +1063,7 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow {
|
||||
},
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
},
|
||||
}
|
||||
"pat" => {
|
||||
const TOKENS: &[&str] = &["`=>`", "`,`", "`=`", "`|`", "`if`", "`in`"];
|
||||
match tok {
|
||||
@ -1052,40 +1074,48 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow {
|
||||
},
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
},
|
||||
}
|
||||
"path" | "ty" => {
|
||||
const TOKENS: &[&str] = &[
|
||||
"`{`", "`[`", "`=>`", "`,`", "`>`","`=`", "`:`", "`;`", "`|`", "`as`",
|
||||
"`{`", "`[`", "`=>`", "`,`", "`>`", "`=`", "`:`", "`;`", "`|`", "`as`",
|
||||
"`where`",
|
||||
];
|
||||
match tok {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
OpenDelim(token::DelimToken::Brace) |
|
||||
OpenDelim(token::DelimToken::Bracket) |
|
||||
Comma | FatArrow | Colon | Eq | Gt | BinOp(token::Shr) | Semi |
|
||||
BinOp(token::Or) => IsInFollow::Yes,
|
||||
Ident(name, false) if name == kw::As ||
|
||||
name == kw::Where => IsInFollow::Yes,
|
||||
OpenDelim(token::DelimToken::Brace)
|
||||
| OpenDelim(token::DelimToken::Bracket)
|
||||
| Comma
|
||||
| FatArrow
|
||||
| Colon
|
||||
| Eq
|
||||
| Gt
|
||||
| BinOp(token::Shr)
|
||||
| Semi
|
||||
| BinOp(token::Or) => IsInFollow::Yes,
|
||||
Ident(name, false) if name == kw::As || name == kw::Where => {
|
||||
IsInFollow::Yes
|
||||
}
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
},
|
||||
TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block =>
|
||||
IsInFollow::Yes,
|
||||
TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::block => {
|
||||
IsInFollow::Yes
|
||||
}
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
},
|
||||
}
|
||||
"ident" | "lifetime" => {
|
||||
// being a single token, idents and lifetimes are harmless
|
||||
IsInFollow::Yes
|
||||
},
|
||||
}
|
||||
"literal" => {
|
||||
// literals may be of a single token, or two tokens (negative numbers)
|
||||
IsInFollow::Yes
|
||||
},
|
||||
}
|
||||
"meta" | "tt" => {
|
||||
// being either a single token or a delimited sequence, tt is
|
||||
// harmless
|
||||
IsInFollow::Yes
|
||||
},
|
||||
}
|
||||
"vis" => {
|
||||
// Explicitly disallow `priv`, on the off chance it comes back.
|
||||
const TOKENS: &[&str] = &["`,`", "an ident", "a type"];
|
||||
@ -1093,30 +1123,39 @@ fn is_in_follow(tok: "ed::TokenTree, frag: &str) -> IsInFollow {
|
||||
TokenTree::Token(token) => match token.kind {
|
||||
Comma => IsInFollow::Yes,
|
||||
Ident(name, is_raw) if is_raw || name != kw::Priv => IsInFollow::Yes,
|
||||
_ => if token.can_begin_type() {
|
||||
IsInFollow::Yes
|
||||
} else {
|
||||
IsInFollow::No(TOKENS)
|
||||
_ => {
|
||||
if token.can_begin_type() {
|
||||
IsInFollow::Yes
|
||||
} else {
|
||||
IsInFollow::No(TOKENS)
|
||||
}
|
||||
}
|
||||
},
|
||||
TokenTree::MetaVarDecl(_, _, frag) if frag.name == sym::ident
|
||||
|| frag.name == sym::ty
|
||||
|| frag.name == sym::path =>
|
||||
IsInFollow::Yes,
|
||||
TokenTree::MetaVarDecl(_, _, frag)
|
||||
if frag.name == sym::ident
|
||||
|| frag.name == sym::ty
|
||||
|| frag.name == sym::path =>
|
||||
{
|
||||
IsInFollow::Yes
|
||||
}
|
||||
_ => IsInFollow::No(TOKENS),
|
||||
}
|
||||
},
|
||||
}
|
||||
"" => IsInFollow::Yes, // kw::Invalid
|
||||
_ => IsInFollow::Invalid(format!("invalid fragment specifier `{}`", frag),
|
||||
VALID_FRAGMENT_NAMES_MSG),
|
||||
_ => IsInFollow::Invalid(
|
||||
format!("invalid fragment specifier `{}`", frag),
|
||||
VALID_FRAGMENT_NAMES_MSG,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_legal_fragment_specifier(sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
tok: "ed::TokenTree) -> Result<(), String> {
|
||||
fn has_legal_fragment_specifier(
|
||||
sess: &ParseSess,
|
||||
features: &Features,
|
||||
attrs: &[ast::Attribute],
|
||||
tok: "ed::TokenTree,
|
||||
) -> Result<(), String> {
|
||||
debug!("has_legal_fragment_specifier({:?})", tok);
|
||||
if let quoted::TokenTree::MetaVarDecl(_, _, ref frag_spec) = *tok {
|
||||
let frag_span = tok.span();
|
||||
@ -1127,11 +1166,13 @@ fn has_legal_fragment_specifier(sess: &ParseSess,
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn is_legal_fragment_specifier(_sess: &ParseSess,
|
||||
_features: &Features,
|
||||
_attrs: &[ast::Attribute],
|
||||
frag_name: Symbol,
|
||||
_frag_span: Span) -> bool {
|
||||
fn is_legal_fragment_specifier(
|
||||
_sess: &ParseSess,
|
||||
_features: &Features,
|
||||
_attrs: &[ast::Attribute],
|
||||
frag_name: Symbol,
|
||||
_frag_span: Span,
|
||||
) -> bool {
|
||||
/*
|
||||
* If new fragment specifiers are invented in nightly, `_sess`,
|
||||
* `_features`, `_attrs`, and `_frag_span` will be useful here
|
||||
@ -1139,9 +1180,20 @@ fn is_legal_fragment_specifier(_sess: &ParseSess,
|
||||
* this function.
|
||||
*/
|
||||
match frag_name {
|
||||
sym::item | sym::block | sym::stmt | sym::expr | sym::pat |
|
||||
sym::lifetime | sym::path | sym::ty | sym::ident | sym::meta | sym::tt |
|
||||
sym::vis | sym::literal | kw::Invalid => true,
|
||||
sym::item
|
||||
| sym::block
|
||||
| sym::stmt
|
||||
| sym::expr
|
||||
| sym::pat
|
||||
| sym::lifetime
|
||||
| sym::path
|
||||
| sym::ty
|
||||
| sym::ident
|
||||
| sym::meta
|
||||
| sym::tt
|
||||
| sym::vis
|
||||
| sym::literal
|
||||
| kw::Invalid => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
@ -1151,7 +1203,9 @@ fn quoted_tt_to_string(tt: "ed::TokenTree) -> String {
|
||||
quoted::TokenTree::Token(ref token) => crate::print::pprust::token_to_string(&token),
|
||||
quoted::TokenTree::MetaVar(_, name) => format!("${}", name),
|
||||
quoted::TokenTree::MetaVarDecl(_, name, kind) => format!("${}:{}", name, kind),
|
||||
_ => panic!("unexpected quoted::TokenTree::{{Sequence or Delimited}} \
|
||||
in follow set checker"),
|
||||
_ => panic!(
|
||||
"unexpected quoted::TokenTree::{{Sequence or Delimited}} \
|
||||
in follow set checker"
|
||||
),
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
use crate::ast;
|
||||
use crate::ast::NodeId;
|
||||
use crate::ext::tt::macro_parser;
|
||||
use crate::feature_gate::Features;
|
||||
use crate::parse::token::{self, Token, TokenKind};
|
||||
use crate::parse::ParseSess;
|
||||
use crate::print::pprust;
|
||||
use crate::tokenstream::{self, DelimSpan};
|
||||
use crate::ast;
|
||||
use crate::symbol::kw;
|
||||
use crate::tokenstream::{self, DelimSpan};
|
||||
|
||||
use syntax_pos::{edition::Edition, BytePos, Span};
|
||||
|
||||
@ -137,8 +137,7 @@ pub fn span(&self) -> Span {
|
||||
TokenTree::Token(Token { span, .. })
|
||||
| TokenTree::MetaVar(span, _)
|
||||
| TokenTree::MetaVarDecl(span, _, _) => span,
|
||||
TokenTree::Delimited(span, _)
|
||||
| TokenTree::Sequence(span, _) => span.entire(),
|
||||
TokenTree::Delimited(span, _) | TokenTree::Sequence(span, _) => span.entire(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,7 +198,7 @@ pub fn parse(
|
||||
match tree {
|
||||
TokenTree::MetaVar(start_sp, ident) if expect_matchers => {
|
||||
let span = match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) =>
|
||||
Some(tokenstream::TokenTree::Token(Token { kind: token::Colon, span })) => {
|
||||
match trees.next() {
|
||||
Some(tokenstream::TokenTree::Token(token)) => match token.ident() {
|
||||
Some((kind, _)) => {
|
||||
@ -209,22 +208,13 @@ pub fn parse(
|
||||
}
|
||||
_ => token.span,
|
||||
},
|
||||
tree => tree
|
||||
.as_ref()
|
||||
.map(tokenstream::TokenTree::span)
|
||||
.unwrap_or(span),
|
||||
},
|
||||
tree => tree
|
||||
.as_ref()
|
||||
.map(tokenstream::TokenTree::span)
|
||||
.unwrap_or(start_sp),
|
||||
tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span),
|
||||
}
|
||||
}
|
||||
tree => tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(start_sp),
|
||||
};
|
||||
sess.missing_fragment_specifiers.borrow_mut().insert(span);
|
||||
result.push(TokenTree::MetaVarDecl(
|
||||
span,
|
||||
ident,
|
||||
ast::Ident::invalid(),
|
||||
));
|
||||
result.push(TokenTree::MetaVarDecl(span, ident, ast::Ident::invalid()));
|
||||
}
|
||||
|
||||
// Not a metavar or no matchers allowed, so just return the tree
|
||||
@ -311,10 +301,8 @@ fn parse_tree(
|
||||
|
||||
// `tree` is followed by a random token. This is an error.
|
||||
Some(tokenstream::TokenTree::Token(token)) => {
|
||||
let msg = format!(
|
||||
"expected identifier, found `{}`",
|
||||
pprust::token_to_string(&token),
|
||||
);
|
||||
let msg =
|
||||
format!("expected identifier, found `{}`", pprust::token_to_string(&token),);
|
||||
sess.span_diagnostic.span_err(token.span, &msg);
|
||||
TokenTree::MetaVar(token.span, ast::Ident::invalid())
|
||||
}
|
||||
@ -371,10 +359,7 @@ fn parse_kleene_op(
|
||||
Some(op) => Ok(Ok((op, token.span))),
|
||||
None => Ok(Err(token)),
|
||||
},
|
||||
tree => Err(tree
|
||||
.as_ref()
|
||||
.map(tokenstream::TokenTree::span)
|
||||
.unwrap_or(span)),
|
||||
tree => Err(tree.as_ref().map(tokenstream::TokenTree::span).unwrap_or(span)),
|
||||
}
|
||||
}
|
||||
|
||||
@ -426,8 +411,7 @@ fn parse_sep_and_kleene_op(
|
||||
};
|
||||
|
||||
// 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.span_diagnostic.span_err(span, "expected one of: `*`, `+`, or `?`");
|
||||
|
||||
// Return a dummy
|
||||
(None, KleeneOp::ZeroOrMore)
|
||||
|
Loading…
Reference in New Issue
Block a user