Skip to content

Commit

Permalink
Auto merge of rust-lang#114292 - estebank:issue-71039, r=<try>
Browse files Browse the repository at this point in the history
More detail when expecting expression but encountering bad macro argument

Partially address rust-lang#71039.

```
error: expected expression, found `1 + 1`
  --> $DIR/trace_faulty_macros.rs:49:37
   |
LL |     (let $p:pat = $e:expr) => {test!(($p,$e))};
   |                                          -- this is interpreted as pattern `1 + 1` (in expansion #2)
...
LL |     (($p:pat, $e:pat)) => {let $p = $e;};
   |                                     ^^ expected expression
...
LL |     test!(let x = 1+1);
   |     ------------------
   |     |             |
   |     |             this is interpreted as expression `1 + 1` (in expansion #1)
   |     in this macro invocation
   |
   = note: this error originates in the macro `test` (in Nightly builds, run with -Z macro-backtrace for more info)
```
  • Loading branch information
bors committed Oct 10, 2023
2 parents d627cf0 + 24c4fa0 commit 06d28f4
Show file tree
Hide file tree
Showing 28 changed files with 328 additions and 160 deletions.
36 changes: 18 additions & 18 deletions compiler/rustc_ast/src/ast_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,29 +231,29 @@ impl HasTokens for Attribute {
impl HasTokens for Nonterminal {
fn tokens(&self) -> Option<&LazyAttrTokenStream> {
match self {
Nonterminal::NtItem(item) => item.tokens(),
Nonterminal::NtStmt(stmt) => stmt.tokens(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens(),
Nonterminal::NtPat(pat) => pat.tokens(),
Nonterminal::NtTy(ty) => ty.tokens(),
Nonterminal::NtMeta(attr_item) => attr_item.tokens(),
Nonterminal::NtPath(path) => path.tokens(),
Nonterminal::NtVis(vis) => vis.tokens(),
Nonterminal::NtBlock(block) => block.tokens(),
Nonterminal::NtItem(item, _) => item.tokens(),
Nonterminal::NtStmt(stmt, _) => stmt.tokens(),
Nonterminal::NtExpr(expr, _) | Nonterminal::NtLiteral(expr, _) => expr.tokens(),
Nonterminal::NtPat(pat, _) => pat.tokens(),
Nonterminal::NtTy(ty, _) => ty.tokens(),
Nonterminal::NtMeta(attr_item, _) => attr_item.tokens(),
Nonterminal::NtPath(path, _) => path.tokens(),
Nonterminal::NtVis(vis, _) => vis.tokens(),
Nonterminal::NtBlock(block, _) => block.tokens(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
fn tokens_mut(&mut self) -> Option<&mut Option<LazyAttrTokenStream>> {
match self {
Nonterminal::NtItem(item) => item.tokens_mut(),
Nonterminal::NtStmt(stmt) => stmt.tokens_mut(),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => expr.tokens_mut(),
Nonterminal::NtPat(pat) => pat.tokens_mut(),
Nonterminal::NtTy(ty) => ty.tokens_mut(),
Nonterminal::NtMeta(attr_item) => attr_item.tokens_mut(),
Nonterminal::NtPath(path) => path.tokens_mut(),
Nonterminal::NtVis(vis) => vis.tokens_mut(),
Nonterminal::NtBlock(block) => block.tokens_mut(),
Nonterminal::NtItem(item, _) => item.tokens_mut(),
Nonterminal::NtStmt(stmt, _) => stmt.tokens_mut(),
Nonterminal::NtExpr(expr, _) | Nonterminal::NtLiteral(expr, _) => expr.tokens_mut(),
Nonterminal::NtPat(pat, _) => pat.tokens_mut(),
Nonterminal::NtTy(ty, _) => ty.tokens_mut(),
Nonterminal::NtMeta(attr_item, _) => attr_item.tokens_mut(),
Nonterminal::NtPath(path, _) => path.tokens_mut(),
Nonterminal::NtVis(vis, _) => vis.tokens_mut(),
Nonterminal::NtBlock(block, _) => block.tokens_mut(),
Nonterminal::NtIdent(..) | Nonterminal::NtLifetime(..) => None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_ast/src/attr/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -343,8 +343,8 @@ impl MetaItem {
Path { span, segments, tokens: None }
}
Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. }, _)) => match &**nt {
token::Nonterminal::NtMeta(item) => return item.meta(item.path.span),
token::Nonterminal::NtPath(path) => (**path).clone(),
token::Nonterminal::NtMeta(item, _) => return item.meta(item.path.span),
token::Nonterminal::NtPath(path, _) => (**path).clone(),
_ => return None,
},
_ => return None,
Expand Down
24 changes: 12 additions & 12 deletions compiler/rustc_ast/src/mut_visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -793,33 +793,33 @@ pub fn visit_token<T: MutVisitor>(t: &mut Token, vis: &mut T) {
// multiple items there....
pub fn visit_nonterminal<T: MutVisitor>(nt: &mut token::Nonterminal, vis: &mut T) {
match nt {
token::NtItem(item) => visit_clobber(item, |item| {
token::NtItem(item, _) => visit_clobber(item, |item| {
// This is probably okay, because the only visitors likely to
// peek inside interpolated nodes will be renamings/markings,
// which map single items to single items.
vis.flat_map_item(item).expect_one("expected visitor to produce exactly one item")
}),
token::NtBlock(block) => vis.visit_block(block),
token::NtStmt(stmt) => visit_clobber(stmt, |stmt| {
token::NtBlock(block, _) => vis.visit_block(block),
token::NtStmt(stmt, _) => visit_clobber(stmt, |stmt| {
// See reasoning above.
stmt.map(|stmt| {
vis.flat_map_stmt(stmt).expect_one("expected visitor to produce exactly one item")
})
}),
token::NtPat(pat) => vis.visit_pat(pat),
token::NtExpr(expr) => vis.visit_expr(expr),
token::NtTy(ty) => vis.visit_ty(ty),
token::NtIdent(ident, _is_raw) => vis.visit_ident(ident),
token::NtLifetime(ident) => vis.visit_ident(ident),
token::NtLiteral(expr) => vis.visit_expr(expr),
token::NtMeta(item) => {
token::NtPat(pat, _) => vis.visit_pat(pat),
token::NtExpr(expr, _) => vis.visit_expr(expr),
token::NtTy(ty, _) => vis.visit_ty(ty),
token::NtIdent(ident, _is_raw, _) => vis.visit_ident(ident),
token::NtLifetime(ident, _) => vis.visit_ident(ident),
token::NtLiteral(expr, _) => vis.visit_expr(expr),
token::NtMeta(item, _) => {
let AttrItem { path, args, tokens } = item.deref_mut();
vis.visit_path(path);
visit_attr_args(args, vis);
visit_lazy_tts(tokens, vis);
}
token::NtPath(path) => vis.visit_path(path),
token::NtVis(visib) => vis.visit_vis(visib),
token::NtPath(path, _) => vis.visit_path(path),
token::NtVis(visib, _) => vis.visit_vis(visib),
}
}

Expand Down
104 changes: 69 additions & 35 deletions compiler/rustc_ast/src/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ impl Lit {
}
Literal(token_lit) => Some(token_lit),
Interpolated(ref nt)
if let NtExpr(expr) | NtLiteral(expr) = &**nt
if let NtExpr(expr, _) | NtLiteral(expr, _) = &**nt
&& let ast::ExprKind::Lit(token_lit) = expr.kind =>
{
Some(token_lit)
Expand Down Expand Up @@ -395,7 +395,7 @@ impl Token {
/// if they keep spans or perform edition checks.
pub fn uninterpolated_span(&self) -> Span {
match &self.kind {
Interpolated(nt) => nt.span(),
Interpolated(nt) => nt.use_span(),
_ => self.span,
}
}
Expand Down Expand Up @@ -551,8 +551,8 @@ impl Token {
Literal(..) | BinOp(Minus) => true,
Ident(name, false) if name.is_bool_lit() => true,
Interpolated(ref nt) => match &**nt {
NtLiteral(_) => true,
NtExpr(e) => match &e.kind {
NtLiteral(..) => true,
NtExpr(e, _) => match &e.kind {
ast::ExprKind::Lit(_) => true,
ast::ExprKind::Unary(ast::UnOp::Neg, e) => {
matches!(&e.kind, ast::ExprKind::Lit(_))
Expand All @@ -572,10 +572,10 @@ impl Token {
pub fn uninterpolate(&self) -> Cow<'_, Token> {
match &self.kind {
Interpolated(nt) => match **nt {
NtIdent(ident, is_raw) => {
NtIdent(ident, is_raw, _) => {
Cow::Owned(Token::new(Ident(ident.name, is_raw), ident.span))
}
NtLifetime(ident) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
NtLifetime(ident, _) => Cow::Owned(Token::new(Lifetime(ident.name), ident.span)),
_ => Cow::Borrowed(self),
},
_ => Cow::Borrowed(self),
Expand All @@ -589,7 +589,7 @@ impl Token {
match &self.kind {
&Ident(name, is_raw) => Some((Ident::new(name, self.span), is_raw)),
Interpolated(nt) => match **nt {
NtIdent(ident, is_raw) => Some((ident, is_raw)),
NtIdent(ident, is_raw, _) => Some((ident, is_raw)),
_ => None,
},
_ => None,
Expand All @@ -603,7 +603,7 @@ impl Token {
match &self.kind {
&Lifetime(name) => Some(Ident::new(name, self.span)),
Interpolated(nt) => match **nt {
NtLifetime(ident) => Some(ident),
NtLifetime(ident, _) => Some(ident),
_ => None,
},
_ => None,
Expand Down Expand Up @@ -640,7 +640,7 @@ impl Token {
/// (which happens while parsing the result of macro expansion)?
pub fn is_whole_expr(&self) -> bool {
if let Interpolated(nt) = &self.kind
&& let NtExpr(_) | NtLiteral(_) | NtPath(_) | NtBlock(_) = **nt
&& let NtExpr(..) | NtLiteral(..) | NtPath(..) | NtBlock(..) = **nt
{
return true;
}
Expand Down Expand Up @@ -803,19 +803,19 @@ impl PartialEq<TokenKind> for Token {
#[derive(Clone, Encodable, Decodable)]
/// For interpolation during macro expansion.
pub enum Nonterminal {
NtItem(P<ast::Item>),
NtBlock(P<ast::Block>),
NtStmt(P<ast::Stmt>),
NtPat(P<ast::Pat>),
NtExpr(P<ast::Expr>),
NtTy(P<ast::Ty>),
NtIdent(Ident, /* is_raw */ bool),
NtLifetime(Ident),
NtLiteral(P<ast::Expr>),
NtItem(P<ast::Item>, Span),
NtBlock(P<ast::Block>, Span),
NtStmt(P<ast::Stmt>, Span),
NtPat(P<ast::Pat>, Span),
NtExpr(P<ast::Expr>, Span),
NtTy(P<ast::Ty>, Span),
NtIdent(Ident, /* is_raw */ bool, Span),
NtLifetime(Ident, Span),
NtLiteral(P<ast::Expr>, Span),
/// Stuff inside brackets for attributes
NtMeta(P<ast::AttrItem>),
NtPath(P<ast::Path>),
NtVis(P<ast::Visibility>),
NtMeta(P<ast::AttrItem>, Span),
NtPath(P<ast::Path>, Span),
NtVis(P<ast::Visibility>, Span),
}

#[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)]
Expand Down Expand Up @@ -897,29 +897,63 @@ impl fmt::Display for NonterminalKind {
}

impl Nonterminal {
pub fn span(&self) -> Span {
pub fn use_span(&self) -> Span {
match self {
NtItem(item) => item.span,
NtBlock(block) => block.span,
NtStmt(stmt) => stmt.span,
NtPat(pat) => pat.span,
NtExpr(expr) | NtLiteral(expr) => expr.span,
NtTy(ty) => ty.span,
NtIdent(ident, _) | NtLifetime(ident) => ident.span,
NtMeta(attr_item) => attr_item.span(),
NtPath(path) => path.span,
NtVis(vis) => vis.span,
NtItem(item, _) => item.span,
NtBlock(block, _) => block.span,
NtStmt(stmt, _) => stmt.span,
NtPat(pat, _) => pat.span,
NtExpr(expr, _) | NtLiteral(expr, _) => expr.span,
NtTy(ty, _) => ty.span,
NtIdent(ident, _, _) | NtLifetime(ident, _) => ident.span,
NtMeta(attr_item, _) => attr_item.span(),
NtPath(path, _) => path.span,
NtVis(vis, _) => vis.span,
}
}

pub fn def_span(&self) -> Span {
match self {
NtItem(_, span)
| NtBlock(_, span)
| NtStmt(_, span)
| NtPat(_, span)
| NtExpr(_, span)
| NtLiteral(_, span)
| NtTy(_, span)
| NtIdent(_, _, span)
| NtLifetime(_, span)
| NtMeta(_, span)
| NtPath(_, span)
| NtVis(_, span) => *span,
}
}

pub fn descr(&self) -> &'static str {
match self {
NtItem(..) => "item",
NtBlock(..) => "block",
NtStmt(..) => "statement",
NtPat(..) => "pattern",
NtExpr(..) => "expression",
NtLiteral(..) => "literal",
NtTy(..) => "type",
NtIdent(..) => "identifier",
NtLifetime(..) => "lifetime",
NtMeta(..) => "attribute",
NtPath(..) => "path",
NtVis(..) => "visibility",
}
}
}

impl PartialEq for Nonterminal {
fn eq(&self, rhs: &Self) -> bool {
match (self, rhs) {
(NtIdent(ident_lhs, is_raw_lhs), NtIdent(ident_rhs, is_raw_rhs)) => {
(NtIdent(ident_lhs, is_raw_lhs, _), NtIdent(ident_rhs, is_raw_rhs, _)) => {
ident_lhs == ident_rhs && is_raw_lhs == is_raw_rhs
}
(NtLifetime(ident_lhs), NtLifetime(ident_rhs)) => ident_lhs == ident_rhs,
(NtLifetime(ident_lhs, _), NtLifetime(ident_rhs, _)) => ident_lhs == ident_rhs,
// FIXME: Assume that all "complex" nonterminal are not equal, we can't compare them
// correctly based on data from AST. This will prevent them from matching each other
// in macros. The comparison will become possible only when each nonterminal has an
Expand Down Expand Up @@ -965,7 +999,7 @@ mod size_asserts {
// tidy-alphabetical-start
static_assert_size!(Lit, 12);
static_assert_size!(LitKind, 2);
static_assert_size!(Nonterminal, 16);
static_assert_size!(Nonterminal, 24);
static_assert_size!(Token, 24);
static_assert_size!(TokenKind, 16);
// tidy-alphabetical-end
Expand Down
26 changes: 13 additions & 13 deletions compiler/rustc_ast/src/tokenstream.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,31 +453,31 @@ impl TokenStream {

pub fn from_nonterminal_ast(nt: &Nonterminal) -> TokenStream {
match nt {
Nonterminal::NtIdent(ident, is_raw) => {
Nonterminal::NtIdent(ident, is_raw, _) => {
TokenStream::token_alone(token::Ident(ident.name, *is_raw), ident.span)
}
Nonterminal::NtLifetime(ident) => {
Nonterminal::NtLifetime(ident, _) => {
TokenStream::token_alone(token::Lifetime(ident.name), ident.span)
}
Nonterminal::NtItem(item) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt) if let StmtKind::Empty = stmt.kind => {
Nonterminal::NtItem(item, _) => TokenStream::from_ast(item),
Nonterminal::NtBlock(block, _) => TokenStream::from_ast(block),
Nonterminal::NtStmt(stmt, _) if let StmtKind::Empty = stmt.kind => {
// FIXME: Properly collect tokens for empty statements.
TokenStream::token_alone(token::Semi, stmt.span)
}
Nonterminal::NtStmt(stmt) => TokenStream::from_ast(stmt),
Nonterminal::NtPat(pat) => TokenStream::from_ast(pat),
Nonterminal::NtTy(ty) => TokenStream::from_ast(ty),
Nonterminal::NtMeta(attr) => TokenStream::from_ast(attr),
Nonterminal::NtPath(path) => TokenStream::from_ast(path),
Nonterminal::NtVis(vis) => TokenStream::from_ast(vis),
Nonterminal::NtExpr(expr) | Nonterminal::NtLiteral(expr) => TokenStream::from_ast(expr),
Nonterminal::NtStmt(stmt, _) => TokenStream::from_ast(stmt),
Nonterminal::NtPat(pat, _) => TokenStream::from_ast(pat),
Nonterminal::NtTy(ty, _) => TokenStream::from_ast(ty),
Nonterminal::NtMeta(attr, _) => TokenStream::from_ast(attr),
Nonterminal::NtPath(path, _) => TokenStream::from_ast(path),
Nonterminal::NtVis(vis, _) => TokenStream::from_ast(vis),
Nonterminal::NtExpr(expr, _) | Nonterminal::NtLiteral(expr, _) => TokenStream::from_ast(expr),
}
}

fn flatten_token(token: &Token, spacing: Spacing) -> TokenTree {
match &token.kind {
token::Interpolated(nt) if let token::NtIdent(ident, is_raw) = **nt => {
token::Interpolated(nt) if let token::NtIdent(ident, is_raw, _) = **nt => {
TokenTree::Token(Token::new(token::Ident(ident.name, is_raw), ident.span), spacing)
}
token::Interpolated(nt) => TokenTree::Delimited(
Expand Down
24 changes: 12 additions & 12 deletions compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -731,18 +731,18 @@ pub trait PrintState<'a>: std::ops::Deref<Target = pp::Printer> + std::ops::Dere

fn nonterminal_to_string(&self, nt: &Nonterminal) -> String {
match nt {
token::NtExpr(e) => self.expr_to_string(e),
token::NtMeta(e) => self.attr_item_to_string(e),
token::NtTy(e) => self.ty_to_string(e),
token::NtPath(e) => self.path_to_string(e),
token::NtItem(e) => self.item_to_string(e),
token::NtBlock(e) => self.block_to_string(e),
token::NtStmt(e) => self.stmt_to_string(e),
token::NtPat(e) => self.pat_to_string(e),
token::NtIdent(e, is_raw) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
token::NtLifetime(e) => e.to_string(),
token::NtLiteral(e) => self.expr_to_string(e),
token::NtVis(e) => self.vis_to_string(e),
token::NtExpr(e, _) => self.expr_to_string(e),
token::NtMeta(e, _) => self.attr_item_to_string(e),
token::NtTy(e, _) => self.ty_to_string(e),
token::NtPath(e, _) => self.path_to_string(e),
token::NtItem(e, _) => self.item_to_string(e),
token::NtBlock(e, _) => self.block_to_string(e),
token::NtStmt(e, _) => self.stmt_to_string(e),
token::NtPat(e, _) => self.pat_to_string(e),
token::NtIdent(e, is_raw, _) => IdentPrinter::for_ast_ident(*e, *is_raw).to_string(),
token::NtLifetime(e, _) => e.to_string(),
token::NtLiteral(e, _) => self.expr_to_string(e),
token::NtVis(e, _) => self.vis_to_string(e),
}
}

Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_expand/src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1498,8 +1498,8 @@ pub(crate) fn ann_pretty_printing_compatibility_hack(ann: &Annotatable, sess: &P

pub(crate) fn nt_pretty_printing_compatibility_hack(nt: &Nonterminal, sess: &ParseSess) -> bool {
let item = match nt {
Nonterminal::NtItem(item) => item,
Nonterminal::NtStmt(stmt) => match &stmt.kind {
Nonterminal::NtItem(item, _) => item,
Nonterminal::NtStmt(stmt, _) => match &stmt.kind {
ast::StmtKind::Item(item) => item,
_ => return false,
},
Expand Down
Loading

0 comments on commit 06d28f4

Please sign in to comment.