NtExpr(..) | NtBlock(..) | NtLiteral(..) => true,
_ => false,
},
- _ => self.can_begin_literal_or_bool(),
+ _ => self.can_begin_literal_maybe_minus(),
}
}
/// Returns `true` if the token is any literal, a minus (which can prefix a literal,
/// for example a '-42', or one of the boolean idents).
///
- /// Keep this in sync with `Lit::from_token`.
- pub fn can_begin_literal_or_bool(&self) -> bool {
+ /// In other words, would this token be a valid start of `parse_literal_maybe_minus`?
+ ///
+ /// Keep this in sync with and `Lit::from_token`, excluding unary negation.
+ pub fn can_begin_literal_maybe_minus(&self) -> bool {
match self.uninterpolate().kind {
Literal(..) | BinOp(Minus) => true,
Ident(name, false) if name.is_bool_lit() => true,
Interpolated(ref nt) => match &**nt {
- NtExpr(e) | NtLiteral(e) => matches!(e.kind, ast::ExprKind::Lit(_)),
+ NtLiteral(_) => true,
+ NtExpr(e) => match &e.kind {
+ ast::ExprKind::Lit(_) => true,
+ ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
+ matches!(&e.kind, ast::ExprKind::Lit(_))
+ }
+ _ => false,
+ },
_ => false,
},
_ => false,
/// Converts arbitrary token into an AST literal.
///
- /// Keep this in sync with `Token::can_begin_literal_or_bool`.
+ /// Keep this in sync with `Token::can_begin_literal_or_bool` excluding unary negation.
pub fn from_token(token: &Token) -> Result<Lit, LitError> {
let lit = match token.uninterpolate().kind {
token::Ident(name, false) if name.is_bool_lit() => {
}
sym::ty => token.can_begin_type(),
sym::ident => get_macro_ident(token).is_some(),
- sym::literal => token.can_begin_literal_or_bool(),
+ sym::literal => token.can_begin_literal_maybe_minus(),
sym::vis => match token.kind {
// The follow-set of :vis + "priv" keyword + interpolated
token::Comma | token::Ident(..) | token::Interpolated(_) => true,
}
/// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`).
+ /// Keep this in sync with `Token::can_begin_literal_maybe_minus`.
pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P<Expr>> {
maybe_whole_expr!(self);
})
// `extern ABI fn`
|| self.check_keyword(kw::Extern)
- && self.look_ahead(1, |t| t.can_begin_literal_or_bool())
+ && self.look_ahead(1, |t| t.can_begin_literal_maybe_minus())
&& self.look_ahead(2, |t| t.is_keyword(kw::Fn))
}
self.look_ahead(dist, |t| {
t.is_path_start() // e.g. `MY_CONST`;
|| t.kind == token::Dot // e.g. `.5` for recovery;
- || t.can_begin_literal_or_bool() // e.g. `42`.
+ || t.can_begin_literal_maybe_minus() // e.g. `42`.
|| t.is_whole_expr()
})
}
// check-pass
// In this test we check that the parser accepts an ABI string when it
-// comes from a macro `literal` fragment as opposed to a hardcoded string.
+// comes from a macro `literal` or `expr` fragment as opposed to a hardcoded string.
fn main() {}
}
}
+macro_rules! abi_from_expr_frag {
+ ($abi:expr) => {
+ extern $abi {
+ fn _import();
+ }
+
+ extern $abi fn _export() {}
+
+ type _PTR = extern $abi fn();
+ };
+}
+
mod rust {
abi_from_lit_frag!("Rust");
}
mod c {
abi_from_lit_frag!("C");
}
+
+mod rust_expr {
+ abi_from_expr_frag!("Rust");
+}
+
+mod c_expr {
+ abi_from_expr_frag!("C");
+}
--- /dev/null
+// check-pass
+
+macro_rules! foo {
+ ($a:literal) => {
+ bar!($a)
+ };
+}
+
+macro_rules! bar {
+ ($b:literal) => {};
+}
+
+fn main() {
+ foo!(-2);
+ bar!(-2);
+}