From a3fce72a27ee41077c3752851ff778f886f0a4fa Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:09 +0100 Subject: [PATCH 1/3] Add `ast::ExprKind::Dummy` --- compiler/rustc_ast/src/ast.rs | 18 ++++-------------- compiler/rustc_ast/src/mut_visit.rs | 4 ++-- compiler/rustc_ast/src/util/classify.rs | 3 ++- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 6 ++++++ compiler/rustc_ast_lowering/src/pat.rs | 3 ++- .../rustc_ast_pretty/src/pprust/state/expr.rs | 5 +++++ .../rustc_builtin_macros/src/assert/context.rs | 1 + compiler/rustc_builtin_macros/src/concat.rs | 1 + .../rustc_builtin_macros/src/concat_bytes.rs | 1 + compiler/rustc_expand/src/base.rs | 3 +++ compiler/rustc_parse/src/parser/expr.rs | 3 ++- compiler/rustc_parse/src/parser/pat.rs | 2 +- compiler/rustc_passes/src/hir_stats.rs | 2 +- src/tools/clippy/clippy_utils/src/ast_utils.rs | 1 + src/tools/clippy/clippy_utils/src/sugg.rs | 3 ++- src/tools/rustfmt/src/expr.rs | 2 +- src/tools/rustfmt/src/utils.rs | 1 + 18 files changed, 37 insertions(+), 24 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 3fdb2a2225a58..b30324c766675 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1296,23 +1296,10 @@ impl Expr { ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::Err => ExprPrecedence::Err, + ExprKind::Err | ExprKind::Dummy => ExprPrecedence::Err, } } - pub fn take(&mut self) -> Self { - mem::replace( - self, - Expr { - id: DUMMY_NODE_ID, - kind: ExprKind::Err, - span: DUMMY_SP, - attrs: AttrVec::new(), - tokens: None, - }, - ) - } - /// To a first-order approximation, is this a pattern? pub fn is_approximately_pattern(&self) -> bool { matches!( @@ -1532,6 +1519,9 @@ pub enum ExprKind { /// Placeholder for an expression that wasn't syntactically well formed in some way. Err, + + /// Acts as a null expression. Lowering it will always emit a bug. + Dummy, } /// Used to differentiate between `for` loops and `for await` loops. diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index c42c41999732c..b2f3bb303de6c 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1526,7 +1526,7 @@ pub fn noop_visit_expr( } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} } vis.visit_id(id); vis.visit_span(span); @@ -1642,7 +1642,7 @@ impl DummyAstNode for Expr { fn dummy() -> Self { Expr { id: DUMMY_NODE_ID, - kind: ExprKind::Err, + kind: ExprKind::Dummy, span: Default::default(), attrs: Default::default(), tokens: Default::default(), diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 098b8f2d6d038..e70a75622e631 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -89,7 +89,8 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { | Paren(_) | Try(_) | Yeet(None) - | Err => break None, + | Err + | Dummy => break None, } } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ecf379cc2408a..ab3d9b496333d 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1063,7 +1063,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} } visitor.visit_expr_post(expression) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index aafa99b3aa6fb..5d33a7a91427f 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -14,6 +14,7 @@ use rustc_ast::*; use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; +use rustc_middle::span_bug; use rustc_session::errors::report_lit_error; use rustc_span::source_map::{respan, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; @@ -331,6 +332,11 @@ impl<'hir> LoweringContext<'_, 'hir> { ExprKind::Err => { hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) } + + ExprKind::Dummy => { + span_bug!(e.span, "lowered ExprKind::Dummy") + } + ExprKind::Try(sub_expr) => self.lower_expr_try(e.span, sub_expr), ExprKind::Paren(_) | ExprKind::ForLoop { .. } => { diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index c097feb6b3476..755b073b2c37b 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -331,7 +331,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::IncludedBytes(..) - | ExprKind::Err => {} + | ExprKind::Err + | ExprKind::Dummy => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} _ => { diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index ff154a009ed05..0f9fe89402b13 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -898,6 +898,11 @@ impl<'a> State<'a> { self.word("/*ERROR*/"); self.pclose() } + ast::ExprKind::Dummy => { + self.popen(); + self.word("/*DUMMY*/"); + self.pclose(); + } } self.ann.post(self, AnnNode::Expr(expr)); diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 01821ee833f1b..7737041090b05 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -303,6 +303,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::Closure(_) | ExprKind::ConstBlock(_) | ExprKind::Continue(_) + | ExprKind::Dummy | ExprKind::Err | ExprKind::Field(_, _) | ExprKind::ForLoop { .. } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 795161e65d81e..691142c03edd0 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -68,6 +68,7 @@ pub fn expand_concat( ast::ExprKind::Err => { has_errors = true; } + ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literal.push(e.span); } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 3ef8cb7bffef2..8ce004586ce84 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -176,6 +176,7 @@ pub fn expand_concat_bytes( ast::ExprKind::Err => { has_errors = true; } + ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literals.push(e.span); } diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 1c8d18bec65cb..762d6745341ae 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1279,6 +1279,9 @@ pub fn expr_to_spanned_string<'a>( _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), }, ast::ExprKind::Err => None, + ast::ExprKind::Dummy => { + cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") + } _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 1ad637451b191..89f28777bffb9 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -3949,7 +3949,8 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Become(_) | ExprKind::IncludedBytes(_) | ExprKind::FormatArgs(_) - | ExprKind::Err => { + | ExprKind::Err + | ExprKind::Dummy => { // These would forbid any let expressions they contain already. } } diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index 2ede19b11e049..c82b44ac6e100 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -388,7 +388,7 @@ impl<'a> Parser<'a> { // Parse `?`, `.f`, `(arg0, arg1, ...)` or `[expr]` until they've all been eaten. if let Ok(expr) = snapshot .parse_expr_dot_or_call_with( - self.mk_expr_err(pat_span), // equivalent to transforming the parsed pattern into an `Expr` + self.mk_expr(pat_span, ExprKind::Dummy), // equivalent to transforming the parsed pattern into an `Expr` pat_span, AttrVec::new(), ) diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 96429bb778882..be6ba585d2004 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -589,7 +589,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { If, While, ForLoop, Loop, Match, Closure, Block, Await, TryBlock, Assign, AssignOp, Field, Index, Range, Underscore, Path, AddrOf, Break, Continue, Ret, InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, - Become, IncludedBytes, Gen, Err + Become, IncludedBytes, Gen, Err, Dummy ] ); ast_visit::walk_expr(self, e) diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 0467a8a65709a..81a26a12009d1 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -144,6 +144,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, + (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index b355e66b7b12a..7b1b0388b29f3 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -222,7 +222,8 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), + | ast::ExprKind::Err + | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, lhs.as_ref().map_or("".into(), |lhs| { diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 4b86c2acdc538..d46d7c53bdb47 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -404,7 +404,7 @@ pub(crate) fn format_expr( // These do not occur in the AST because macros aren't expanded. unreachable!() } - ast::ExprKind::Err => None, + ast::ExprKind::Err | ast::ExprKind::Dummy => None, }; expr_rw diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index 642b6603b1e9a..b6b37e492e92f 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -497,6 +497,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Break(..) | ast::ExprKind::Cast(..) | ast::ExprKind::Continue(..) + | ast::ExprKind::Dummy | ast::ExprKind::Err | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) From c440a5b814005c85ec903f9b9e44e25bf5c9c565 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:22:11 +0100 Subject: [PATCH 2/3] Add `ErrorGuaranteed` to `ast::ExprKind::Err` --- compiler/rustc_ast/src/ast.rs | 4 +- compiler/rustc_ast/src/mut_visit.rs | 2 +- compiler/rustc_ast/src/util/classify.rs | 2 +- compiler/rustc_ast/src/visit.rs | 2 +- compiler/rustc_ast_lowering/src/expr.rs | 4 +- compiler/rustc_ast_lowering/src/pat.rs | 2 +- .../rustc_ast_pretty/src/pprust/state/expr.rs | 2 +- compiler/rustc_builtin_macros/src/asm.rs | 71 ++++---- compiler/rustc_builtin_macros/src/assert.rs | 4 +- .../src/assert/context.rs | 2 +- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- .../rustc_builtin_macros/src/compile_error.rs | 14 +- compiler/rustc_builtin_macros/src/concat.rs | 35 ++-- .../rustc_builtin_macros/src/concat_bytes.rs | 131 +++++++------- .../rustc_builtin_macros/src/concat_idents.rs | 12 +- .../src/deriving/default.rs | 53 +++--- compiler/rustc_builtin_macros/src/env.rs | 36 ++-- compiler/rustc_builtin_macros/src/format.rs | 90 +++++----- compiler/rustc_builtin_macros/src/lib.rs | 1 + .../rustc_builtin_macros/src/source_util.rs | 43 ++--- .../rustc_builtin_macros/src/type_ascribe.rs | 4 +- compiler/rustc_expand/src/base.rs | 99 ++++++----- compiler/rustc_expand/src/expand.rs | 82 +++++---- compiler/rustc_expand/src/mbe/diagnostics.rs | 18 +- compiler/rustc_expand/src/mbe/macro_check.rs | 62 +++---- compiler/rustc_expand/src/mbe/macro_rules.rs | 132 +++++++------- compiler/rustc_lint/src/unused.rs | 2 +- .../rustc_parse/src/parser/diagnostics.rs | 90 +++++----- compiler/rustc_parse/src/parser/expr.rs | 165 ++++++++++-------- compiler/rustc_parse/src/parser/item.rs | 4 +- compiler/rustc_parse/src/parser/pat.rs | 18 +- compiler/rustc_parse/src/parser/stmt.rs | 64 ++++--- compiler/rustc_parse/src/validate_attr.rs | 2 +- .../clippy/clippy_utils/src/ast_utils.rs | 2 +- src/tools/clippy/clippy_utils/src/sugg.rs | 2 +- src/tools/rustfmt/src/expr.rs | 2 +- src/tools/rustfmt/src/utils.rs | 2 +- 37 files changed, 661 insertions(+), 603 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index b30324c766675..8ba2f222fcfaa 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1296,7 +1296,7 @@ impl Expr { ExprKind::Yeet(..) => ExprPrecedence::Yeet, ExprKind::FormatArgs(..) => ExprPrecedence::FormatArgs, ExprKind::Become(..) => ExprPrecedence::Become, - ExprKind::Err | ExprKind::Dummy => ExprPrecedence::Err, + ExprKind::Err(_) | ExprKind::Dummy => ExprPrecedence::Err, } } @@ -1518,7 +1518,7 @@ pub enum ExprKind { FormatArgs(P), /// Placeholder for an expression that wasn't syntactically well formed in some way. - Err, + Err(ErrorGuaranteed), /// Acts as a null expression. Lowering it will always emit a bug. Dummy, diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index b2f3bb303de6c..60bc21c6441fc 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -1526,7 +1526,7 @@ pub fn noop_visit_expr( } ExprKind::Try(expr) => vis.visit_expr(expr), ExprKind::TryBlock(body) => vis.visit_block(body), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} } vis.visit_id(id); vis.visit_span(span); diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index e70a75622e631..f21a9cabb81be 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -89,7 +89,7 @@ pub fn expr_trailing_brace(mut expr: &ast::Expr) -> Option<&ast::Expr> { | Paren(_) | Try(_) | Yeet(None) - | Err + | Err(_) | Dummy => break None, } } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index ab3d9b496333d..f29022386a9d3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -1063,7 +1063,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) -> V } ExprKind::Try(subexpression) => try_visit!(visitor.visit_expr(subexpression)), ExprKind::TryBlock(body) => try_visit!(visitor.visit_block(body)), - ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err | ExprKind::Dummy => {} + ExprKind::Lit(_) | ExprKind::IncludedBytes(..) | ExprKind::Err(_) | ExprKind::Dummy => {} } visitor.visit_expr_post(expression) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 5d33a7a91427f..9950db4784b9c 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -329,9 +329,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ) } ExprKind::Yield(opt_expr) => self.lower_expr_yield(e.span, opt_expr.as_deref()), - ExprKind::Err => { - hir::ExprKind::Err(self.dcx().span_delayed_bug(e.span, "lowered ExprKind::Err")) - } + ExprKind::Err(guar) => hir::ExprKind::Err(*guar), ExprKind::Dummy => { span_bug!(e.span, "lowered ExprKind::Dummy") diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs index 755b073b2c37b..469cdac11e439 100644 --- a/compiler/rustc_ast_lowering/src/pat.rs +++ b/compiler/rustc_ast_lowering/src/pat.rs @@ -331,7 +331,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { ExprKind::Lit(..) | ExprKind::ConstBlock(..) | ExprKind::IncludedBytes(..) - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Dummy => {} ExprKind::Path(..) if allow_paths => {} ExprKind::Unary(UnOp::Neg, inner) if matches!(inner.kind, ExprKind::Lit(_)) => {} diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index 0f9fe89402b13..433ef03b6e544 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -893,7 +893,7 @@ impl<'a> State<'a> { self.word_nbsp("try"); self.print_block_with_attrs(blk, attrs) } - ast::ExprKind::Err => { + ast::ExprKind::Err(_) => { self.popen(); self.word("/*ERROR*/"); self.pclose() diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 263081ea19ead..29bf5e9f30493 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -13,7 +13,7 @@ use rustc_session::lint; use rustc_session::parse::ParseSess; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym, Symbol}; -use rustc_span::{InnerSpan, Span}; +use rustc_span::{ErrorGuaranteed, InnerSpan, Span}; use rustc_target::asm::InlineAsmArch; use smallvec::smallvec; @@ -433,7 +433,10 @@ fn parse_reg<'a>( Ok(result) } -fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option { +fn expand_preparsed_asm( + ecx: &mut ExtCtxt<'_>, + args: AsmArgs, +) -> Result { let mut template = vec![]; // Register operands are implicitly used since they are not allowed to be // referenced in the template string. @@ -459,10 +462,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option template_part, Err(err) => { - if let Some((err, _)) = err { - err.emit(); - } - return None; + return Err(match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, + }); } }; @@ -551,8 +554,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option, args: AsmArgs) -> Option( ) -> Box { match parse_args(ecx, sp, tts, false) { Ok(args) => { - let expr = if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - P(ast::Expr { + let expr = match expand_preparsed_asm(ecx, args) { + Ok(inline_asm) => P(ast::Expr { id: ast::DUMMY_NODE_ID, kind: ast::ExprKind::InlineAsm(P(inline_asm)), span: sp, attrs: ast::AttrVec::new(), tokens: None, - }) - } else { - DummyResult::raw_expr(sp, true) + }), + Err(guar) => DummyResult::raw_expr(sp, Some(guar)), }; MacEager::expr(expr) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } @@ -762,28 +764,25 @@ pub(super) fn expand_global_asm<'cx>( tts: TokenStream, ) -> Box { match parse_args(ecx, sp, tts, true) { - Ok(args) => { - if let Some(inline_asm) = expand_preparsed_asm(ecx, args) { - MacEager::items(smallvec![P(ast::Item { - ident: Ident::empty(), - attrs: ast::AttrVec::new(), - id: ast::DUMMY_NODE_ID, - kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), - vis: ast::Visibility { - span: sp.shrink_to_lo(), - kind: ast::VisibilityKind::Inherited, - tokens: None, - }, - span: sp, + Ok(args) => match expand_preparsed_asm(ecx, args) { + Ok(inline_asm) => MacEager::items(smallvec![P(ast::Item { + ident: Ident::empty(), + attrs: ast::AttrVec::new(), + id: ast::DUMMY_NODE_ID, + kind: ast::ItemKind::GlobalAsm(Box::new(inline_asm)), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, tokens: None, - })]) - } else { - DummyResult::any(sp) - } - } + }, + span: sp, + tokens: None, + })]), + Err(guar) => DummyResult::any(sp, guar), + }, Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs index 501d557f3ab8a..613ce43dec2d6 100644 --- a/compiler/rustc_builtin_macros/src/assert.rs +++ b/compiler/rustc_builtin_macros/src/assert.rs @@ -23,8 +23,8 @@ pub fn expand_assert<'cx>( let Assert { cond_expr, custom_message } = match parse_assert(cx, span, tts) { Ok(assert) => assert, Err(err) => { - err.emit(); - return DummyResult::any(span); + let guar = err.emit(); + return DummyResult::any(span, guar); } }; diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs index 7737041090b05..56c56b2704b00 100644 --- a/compiler/rustc_builtin_macros/src/assert/context.rs +++ b/compiler/rustc_builtin_macros/src/assert/context.rs @@ -304,7 +304,7 @@ impl<'cx, 'a> Context<'cx, 'a> { | ExprKind::ConstBlock(_) | ExprKind::Continue(_) | ExprKind::Dummy - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Field(_, _) | ExprKind::ForLoop { .. } | ExprKind::FormatArgs(_) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index 581d390992adc..ca66bc0da0cc7 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -29,8 +29,8 @@ pub fn expand_cfg( MacEager::expr(cx.expr_bool(sp, matches_cfg)) } Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index f157575da79bc..6650035127296 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -9,16 +9,14 @@ pub fn expand_compile_error<'cx>( sp: Span, tts: TokenStream, ) -> Box { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "compile_error!") else { - return DummyResult::any(sp); + let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { + Ok(var) => var, + Err(guar) => return DummyResult::any(sp, guar), }; - #[expect( - rustc::diagnostic_outside_of_impl, - reason = "diagnostic message is specified by user" - )] + #[expect(rustc::diagnostic_outside_of_impl, reason = "diagnostic message is specified by user")] #[expect(rustc::untranslatable_diagnostic, reason = "diagnostic message is specified by user")] - cx.dcx().span_err(sp, var.to_string()); + let guar = cx.dcx().span_err(sp, var.to_string()); - DummyResult::any(sp) + DummyResult::any(sp, guar) } diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index 691142c03edd0..dd4a0e7f22869 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -11,12 +11,13 @@ pub fn expand_concat( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); + let es = match base::get_exprs_from_tts(cx, tts) { + Ok(es) => es, + Err(guar) => return DummyResult::any(sp, guar), }; let mut accumulator = String::new(); let mut missing_literal = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match e.kind { ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -33,19 +34,16 @@ pub fn expand_concat( accumulator.push_str(&b.to_string()); } Ok(ast::LitKind::CStr(..)) => { - cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span }); - has_errors = true; + guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); } Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { - cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); - has_errors = true; + guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); } - Ok(ast::LitKind::Err(_)) => { - has_errors = true; + Ok(ast::LitKind::Err(guarantee)) => { + guar = Some(guarantee); } Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } }, // We also want to allow negative numeric literals. @@ -56,8 +54,7 @@ pub fn expand_concat( Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span); - has_errors = true; + guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } _ => missing_literal.push(e.span), } @@ -65,8 +62,8 @@ pub fn expand_concat( ast::ExprKind::IncludedBytes(..) => { cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); } - ast::ExprKind::Err => { - has_errors = true; + ast::ExprKind::Err(guarantee) => { + guar = Some(guarantee); } ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { @@ -76,10 +73,10 @@ pub fn expand_concat( } if !missing_literal.is_empty() { - cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); - return DummyResult::any(sp); - } else if has_errors { - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatMissingLiteral { spans: missing_literal }); + return DummyResult::any(sp, guar); + } else if let Some(guar) = guar { + return DummyResult::any(sp, guar); } let sp = cx.with_def_site_ctxt(sp); base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 8ce004586ce84..32e17112d8c45 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_ast::{ptr::P, tokenstream::TokenStream}; use rustc_expand::base::{self, DummyResult}; use rustc_session::errors::report_lit_error; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use crate::errors; @@ -12,7 +12,7 @@ fn invalid_type_err( token_lit: ast::token::Lit, span: Span, is_nested: bool, -) { +) -> ErrorGuaranteed { use errors::{ ConcatBytesInvalid, ConcatBytesInvalidSuggestion, ConcatBytesNonU8, ConcatBytesOob, }; @@ -22,12 +22,12 @@ fn invalid_type_err( Ok(ast::LitKind::CStr(_, _)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. - dcx.emit_err(errors::ConcatCStrLit { span: span }); + dcx.emit_err(errors::ConcatCStrLit { span }) } Ok(ast::LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) } Ok(ast::LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested @@ -36,86 +36,79 @@ fn invalid_type_err( } else { None }; - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) } Ok(ast::LitKind::Float(_, _)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) } Ok(ast::LitKind::Bool(_)) => { - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) } - Ok(ast::LitKind::Err(_)) => {} Ok(ast::LitKind::Int(_, _)) if !is_nested => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); - dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }); + dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } Ok(ast::LitKind::Int( val, ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), )) => { assert!(val.get() > u8::MAX.into()); // must be an error - dcx.emit_err(ConcatBytesOob { span }); - } - Ok(ast::LitKind::Int(_, _)) => { - dcx.emit_err(ConcatBytesNonU8 { span }); + dcx.emit_err(ConcatBytesOob { span }) } + Ok(ast::LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), - Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, span); - } + Ok(ast::LitKind::Err(guar)) => guar, + Err(err) => report_lit_error(&cx.sess.parse_sess, err, token_lit, span), } } +/// Returns `expr` as a *single* byte literal if applicable. +/// +/// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or +/// updates `guar` accordingly. fn handle_array_element( cx: &mut base::ExtCtxt<'_>, - has_errors: &mut bool, + guar: &mut Option, missing_literals: &mut Vec, expr: &P, ) -> Option { let dcx = cx.dcx(); - match expr.kind { - ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None - } - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) if val.get() <= u8::MAX.into() => Some(val.get() as u8), - Ok(ast::LitKind::Byte(val)) => Some(val), - Ok(ast::LitKind::ByteStr(..)) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }); + match expr.kind { + ast::ExprKind::Lit(token_lit) => { + match ast::LitKind::from_token_lit(token_lit) { + Ok(ast::LitKind::Int( + val, + ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + )) if let Ok(val) = u8::try_from(val.get()) => { + return Some(val); } - *has_errors = true; - None - } - _ => { - if !*has_errors { - invalid_type_err(cx, token_lit, expr.span, true); + Ok(ast::LitKind::Byte(val)) => return Some(val), + Ok(ast::LitKind::ByteStr(..)) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) + }); } - *has_errors = true; - None - } - }, - ast::ExprKind::IncludedBytes(..) => { - if !*has_errors { - dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }); - } - *has_errors = true; - None + _ => { + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, expr.span, true)); + } + }; } - _ => { - missing_literals.push(expr.span); - None + ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); + } + ast::ExprKind::IncludedBytes(..) => { + guar.get_or_insert_with(|| { + dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) + }); } + _ => missing_literals.push(expr.span), } + + None } pub fn expand_concat_bytes( @@ -123,18 +116,19 @@ pub fn expand_concat_bytes( sp: rustc_span::Span, tts: TokenStream, ) -> Box { - let Some(es) = base::get_exprs_from_tts(cx, tts) else { - return DummyResult::any(sp); + let es = match base::get_exprs_from_tts(cx, tts) { + Ok(es) => es, + Err(guar) => return DummyResult::any(sp, guar), }; let mut accumulator = Vec::new(); let mut missing_literals = vec![]; - let mut has_errors = false; + let mut guar = None; for e in es { match &e.kind { ast::ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { accumulator.push(elem); } @@ -146,14 +140,16 @@ pub fn expand_concat_bytes( ast::LitKind::from_token_lit(token_lit) { if let Some(elem) = - handle_array_element(cx, &mut has_errors, &mut missing_literals, expr) + handle_array_element(cx, &mut guar, &mut missing_literals, expr) { for _ in 0..count_val.get() { accumulator.push(elem); } } } else { - cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }); + guar = Some( + cx.dcx().emit_err(errors::ConcatBytesBadRepeat { span: count.value.span }), + ); } } &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { @@ -164,17 +160,14 @@ pub fn expand_concat_bytes( accumulator.extend_from_slice(bytes); } _ => { - if !has_errors { - invalid_type_err(cx, token_lit, e.span, false); - } - has_errors = true; + guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, ast::ExprKind::IncludedBytes(bytes) => { accumulator.extend_from_slice(bytes); } - ast::ExprKind::Err => { - has_errors = true; + ast::ExprKind::Err(guarantee) => { + guar = Some(*guarantee); } ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { @@ -183,10 +176,10 @@ pub fn expand_concat_bytes( } } if !missing_literals.is_empty() { - cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); - } else if has_errors { - return base::MacEager::expr(DummyResult::raw_expr(sp, true)); + let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); + return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + } else if let Some(guar) = guar { + return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } let sp = cx.with_def_site_ctxt(sp); base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 17fd3901cc6bc..29d3f6164aa16 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -14,8 +14,8 @@ pub fn expand_concat_idents<'cx>( tts: TokenStream, ) -> Box { if tts.is_empty() { - cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); + return DummyResult::any(sp, guar); } let mut res_str = String::new(); @@ -24,8 +24,8 @@ pub fn expand_concat_idents<'cx>( match e { TokenTree::Token(Token { kind: token::Comma, .. }, _) => {} _ => { - cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingComma { span: sp }); + return DummyResult::any(sp, guar); } } } else { @@ -36,8 +36,8 @@ pub fn expand_concat_idents<'cx>( } } - cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); - return DummyResult::any(sp); + let guar = cx.dcx().emit_err(errors::ConcatIdentsIdentArgs { span: sp }); + return DummyResult::any(sp, guar); } } diff --git a/compiler/rustc_builtin_macros/src/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs index 0bd2d423a294f..386d4a54b655b 100644 --- a/compiler/rustc_builtin_macros/src/deriving/default.rs +++ b/compiler/rustc_builtin_macros/src/deriving/default.rs @@ -6,7 +6,7 @@ use rustc_ast::{attr, walk_list, EnumDef, VariantData}; use rustc_expand::base::{Annotatable, DummyResult, ExtCtxt}; use rustc_span::symbol::Ident; use rustc_span::symbol::{kw, sym}; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use smallvec::SmallVec; use thin_vec::{thin_vec, ThinVec}; @@ -83,16 +83,19 @@ fn default_enum_substructure( trait_span: Span, enum_def: &EnumDef, ) -> BlockOrExpr { - let expr = if let Ok(default_variant) = extract_default_variant(cx, enum_def, trait_span) - && let Ok(_) = validate_default_attribute(cx, default_variant) - { - // We now know there is exactly one unit variant with exactly one `#[default]` attribute. - cx.expr_path(cx.path( - default_variant.span, - vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], - )) - } else { - DummyResult::raw_expr(trait_span, true) + let expr = match try { + let default_variant = extract_default_variant(cx, enum_def, trait_span)?; + validate_default_attribute(cx, default_variant)?; + default_variant + } { + Ok(default_variant) => { + // We now know there is exactly one unit variant with exactly one `#[default]` attribute. + cx.expr_path(cx.path( + default_variant.span, + vec![Ident::new(kw::SelfUpper, default_variant.span), default_variant.ident], + )) + } + Err(guar) => DummyResult::raw_expr(trait_span, Some(guar)), }; BlockOrExpr::new_expr(expr) } @@ -101,7 +104,7 @@ fn extract_default_variant<'a>( cx: &mut ExtCtxt<'_>, enum_def: &'a EnumDef, trait_span: Span, -) -> Result<&'a rustc_ast::Variant, ()> { +) -> Result<&'a rustc_ast::Variant, ErrorGuaranteed> { let default_variants: SmallVec<[_; 1]> = enum_def .variants .iter() @@ -120,9 +123,9 @@ fn extract_default_variant<'a>( let suggs = possible_defaults .map(|v| errors::NoDefaultVariantSugg { span: v.span, ident: v.ident }) .collect(); - cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); + let guar = cx.dcx().emit_err(errors::NoDefaultVariant { span: trait_span, suggs }); - return Err(()); + return Err(guar); } [first, rest @ ..] => { let suggs = default_variants @@ -140,28 +143,28 @@ fn extract_default_variant<'a>( .then_some(errors::MultipleDefaultsSugg { spans, ident: variant.ident }) }) .collect(); - cx.dcx().emit_err(errors::MultipleDefaults { + let guar = cx.dcx().emit_err(errors::MultipleDefaults { span: trait_span, first: first.span, additional: rest.iter().map(|v| v.span).collect(), suggs, }); - return Err(()); + return Err(guar); } }; if !matches!(variant.data, VariantData::Unit(..)) { - cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); - return Err(()); + let guar = cx.dcx().emit_err(errors::NonUnitDefault { span: variant.ident.span }); + return Err(guar); } if let Some(non_exhaustive_attr) = attr::find_by_name(&variant.attrs, sym::non_exhaustive) { - cx.dcx().emit_err(errors::NonExhaustiveDefault { + let guar = cx.dcx().emit_err(errors::NonExhaustiveDefault { span: variant.ident.span, non_exhaustive: non_exhaustive_attr.span, }); - return Err(()); + return Err(guar); } Ok(variant) @@ -170,7 +173,7 @@ fn extract_default_variant<'a>( fn validate_default_attribute( cx: &mut ExtCtxt<'_>, default_variant: &rustc_ast::Variant, -) -> Result<(), ()> { +) -> Result<(), ErrorGuaranteed> { let attrs: SmallVec<[_; 1]> = attr::filter_by_name(&default_variant.attrs, kw::Default).collect(); @@ -183,7 +186,7 @@ fn validate_default_attribute( let sugg = errors::MultipleDefaultAttrsSugg { spans: rest.iter().map(|attr| attr.span).collect(), }; - cx.dcx().emit_err(errors::MultipleDefaultAttrs { + let guar = cx.dcx().emit_err(errors::MultipleDefaultAttrs { span: default_variant.ident.span, first: first.span, first_rest: rest[0].span, @@ -192,13 +195,13 @@ fn validate_default_attribute( sugg, }); - return Err(()); + return Err(guar); } }; if !attr.is_word() { - cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); + let guar = cx.dcx().emit_err(errors::DefaultHasArg { span: attr.span }); - return Err(()); + return Err(guar); } Ok(()) } diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index a0fd0e3f9be08..67ace546ad042 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -28,8 +28,9 @@ pub fn expand_option_env<'cx>( sp: Span, tts: TokenStream, ) -> Box { - let Some(var) = get_single_str_from_tts(cx, sp, tts, "option_env!") else { - return DummyResult::any(sp); + let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { + Ok(var) => var, + Err(guar) => return DummyResult::any(sp, guar), }; let sp = cx.with_def_site_ctxt(sp); @@ -65,24 +66,25 @@ pub fn expand_env<'cx>( tts: TokenStream, ) -> Box { let mut exprs = match get_exprs_from_tts(cx, tts) { - Some(exprs) if exprs.is_empty() || exprs.len() > 2 => { - cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); - return DummyResult::any(sp); + Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { + let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); + return DummyResult::any(sp, guar); } - None => return DummyResult::any(sp), - Some(exprs) => exprs.into_iter(), + Err(guar) => return DummyResult::any(sp, guar), + Ok(exprs) => exprs.into_iter(), }; let var_expr = exprs.next().unwrap(); - let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else { - return DummyResult::any(sp); + let var = match expr_to_string(cx, var_expr.clone(), "expected string literal") { + Ok((var, _)) => var, + Err(guar) => return DummyResult::any(sp, guar), }; let custom_msg = match exprs.next() { None => None, Some(second) => match expr_to_string(cx, second, "expected string literal") { - None => return DummyResult::any(sp), - Some((s, _)) => Some(s), + Ok((s, _)) => Some(s), + Err(guar) => return DummyResult::any(sp, guar), }, }; @@ -100,23 +102,23 @@ pub fn expand_env<'cx>( unreachable!("`expr_to_string` ensures this is a string lit") }; - if let Some(msg_from_user) = custom_msg { - cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }); + let guar = if let Some(msg_from_user) = custom_msg { + cx.dcx().emit_err(errors::EnvNotDefinedWithUserMessage { span, msg_from_user }) } else if is_cargo_env_var(var.as_str()) { cx.dcx().emit_err(errors::EnvNotDefined::CargoEnvVar { span, var: *symbol, var_expr: var_expr.ast_deref(), - }); + }) } else { cx.dcx().emit_err(errors::EnvNotDefined::CustomEnvVar { span, var: *symbol, var_expr: var_expr.ast_deref(), - }); - } + }) + }; - return DummyResult::any(sp); + return DummyResult::any(sp, guar); } Some(value) => cx.expr_str(span, value), }; diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 3366378d38da8..06c2b6177068a 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -13,7 +13,7 @@ use rustc_expand::base::{self, *}; use rustc_parse::parser::Recovered; use rustc_parse_format as parse; use rustc_span::symbol::{Ident, Symbol}; -use rustc_span::{BytePos, InnerSpan, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, InnerSpan, Span}; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; @@ -160,7 +160,7 @@ fn make_format_args( ecx: &mut ExtCtxt<'_>, input: MacroInput, append_newline: bool, -) -> Result { +) -> Result { let msg = "format argument must be a string literal"; let unexpanded_fmt_span = input.fmtstr.span; @@ -173,38 +173,41 @@ fn make_format_args( } Ok(fmt) => fmt, Err(err) => { - if let Some((mut err, suggested)) = err { - if !suggested { - if let ExprKind::Block(block, None) = &efmt.kind - && block.stmts.len() == 1 - && let StmtKind::Expr(expr) = &block.stmts[0].kind - && let ExprKind::Path(None, path) = &expr.kind - && path.is_potential_trivial_const_arg() - { - err.multipart_suggestion( - "quote your inlined format argument to use as string literal", - vec![ - (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), - (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), - ], - Applicability::MaybeIncorrect, - ); - } else { - let sugg_fmt = match args.explicit_args().len() { - 0 => "{}".to_string(), - _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), - }; - err.span_suggestion( - unexpanded_fmt_span.shrink_to_lo(), - "you might be missing a string literal to format with", - format!("\"{sugg_fmt}\", "), - Applicability::MaybeIncorrect, - ); + let guar = match err { + Ok((mut err, suggested)) => { + if !suggested { + if let ExprKind::Block(block, None) = &efmt.kind + && block.stmts.len() == 1 + && let StmtKind::Expr(expr) = &block.stmts[0].kind + && let ExprKind::Path(None, path) = &expr.kind + && path.is_potential_trivial_const_arg() + { + err.multipart_suggestion( + "quote your inlined format argument to use as string literal", + vec![ + (unexpanded_fmt_span.shrink_to_hi(), "\"".to_string()), + (unexpanded_fmt_span.shrink_to_lo(), "\"".to_string()), + ], + Applicability::MaybeIncorrect, + ); + } else { + let sugg_fmt = match args.explicit_args().len() { + 0 => "{}".to_string(), + _ => format!("{}{{}}", "{} ".repeat(args.explicit_args().len())), + }; + err.span_suggestion( + unexpanded_fmt_span.shrink_to_lo(), + "you might be missing a string literal to format with", + format!("\"{sugg_fmt}\", "), + Applicability::MaybeIncorrect, + ); + } } + err.emit() } - err.emit(); - } - return Err(()); + Err(guar) => guar, + }; + return Err(guar); } }; @@ -293,8 +296,8 @@ fn make_format_args( } } } - ecx.dcx().emit_err(e); - return Err(()); + let guar = ecx.dcx().emit_err(e); + return Err(guar); } let to_span = |inner_span: rustc_parse_format::InnerSpan| { @@ -353,9 +356,9 @@ fn make_format_args( } else { // For the moment capturing variables from format strings expanded from macros is // disabled (see RFC #2795) - ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); + let guar = ecx.dcx().emit_err(errors::FormatNoArgNamed { span, name }); unnamed_arg_after_named_arg = true; - DummyResult::raw_expr(span, true) + DummyResult::raw_expr(span, Some(guar)) }; Ok(args.add(FormatArgument { kind: FormatArgumentKind::Captured(ident), expr })) } @@ -972,16 +975,13 @@ fn expand_format_args_impl<'cx>( ) -> Box { sp = ecx.with_def_site_ctxt(sp); match parse_args(ecx, sp, tts) { - Ok(input) => { - if let Ok(format_args) = make_format_args(ecx, input, nl) { - MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))) - } else { - MacEager::expr(DummyResult::raw_expr(sp, true)) - } - } + Ok(input) => match make_format_args(ecx, input, nl) { + Ok(format_args) => MacEager::expr(ecx.expr(sp, ExprKind::FormatArgs(P(format_args)))), + Err(guar) => MacEager::expr(DummyResult::raw_expr(sp, Some(guar))), + }, Err(err) => { - err.emit(); - DummyResult::any(sp) + let guar = err.emit(); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index d30ccab239437..f344dbcd10c06 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -15,6 +15,7 @@ #![feature(lint_reasons)] #![feature(proc_macro_internals)] #![feature(proc_macro_quote)] +#![feature(try_blocks)] extern crate proc_macro; diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 43d13569d1ee1..3860057e1d412 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -103,15 +103,16 @@ pub fn expand_include<'cx>( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; // The file will be added to the code map by the parser let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; let p = new_parser_from_file(cx.parse_sess(), &file, Some(sp)); @@ -130,7 +131,7 @@ pub fn expand_include<'cx>( } impl<'a> base::MacResult for ExpandResult<'a> { fn make_expr(mut self: Box>) -> Option> { - let r = base::parse_expr(&mut self.p)?; + let expr = base::parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { self.p.sess.buffer_lint( INCOMPLETE_INCLUDE, @@ -139,7 +140,7 @@ pub fn expand_include<'cx>( "include macro expected single expression in source", ); } - Some(r) + Some(expr) } fn make_items(mut self: Box>) -> Option; 1]>> { @@ -176,14 +177,15 @@ pub fn expand_include_str( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_str!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; match cx.source_map().load_binary_file(&file) { @@ -193,13 +195,13 @@ pub fn expand_include_str( base::MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { - cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); + DummyResult::any(sp, guar) } }, Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); + DummyResult::any(sp, guar) } } } @@ -210,14 +212,15 @@ pub fn expand_include_bytes( tts: TokenStream, ) -> Box { let sp = cx.with_def_site_ctxt(sp); - let Some(file) = get_single_str_from_tts(cx, sp, tts, "include_bytes!") else { - return DummyResult::any(sp); + let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { + Ok(file) => file, + Err(guar) => return DummyResult::any(sp, guar), }; let file = match resolve_path(&cx.sess, file.as_str(), sp) { Ok(f) => f, Err(err) => { - err.emit(); - return DummyResult::any(sp); + let guar = err.emit(); + return DummyResult::any(sp, guar); } }; match cx.source_map().load_binary_file(&file) { @@ -226,8 +229,8 @@ pub fn expand_include_bytes( base::MacEager::expr(expr) } Err(e) => { - cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); - DummyResult::any(sp) + let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e)); + DummyResult::any(sp, guar) } } } diff --git a/compiler/rustc_builtin_macros/src/type_ascribe.rs b/compiler/rustc_builtin_macros/src/type_ascribe.rs index 564797012ae26..e8b8fe75338cb 100644 --- a/compiler/rustc_builtin_macros/src/type_ascribe.rs +++ b/compiler/rustc_builtin_macros/src/type_ascribe.rs @@ -13,8 +13,8 @@ pub fn expand_type_ascribe( let (expr, ty) = match parse_ascribe(cx, tts) { Ok(parsed) => parsed, Err(err) => { - err.emit(); - return DummyResult::any(span); + let guar = err.emit(); + return DummyResult::any(span, guar); } }; diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs index 762d6745341ae..7ece46523dbfe 100644 --- a/compiler/rustc_expand/src/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -532,7 +532,7 @@ impl MacResult for MacEager { /// after hitting errors. #[derive(Copy, Clone)] pub struct DummyResult { - is_error: bool, + guar: Option, span: Span, } @@ -541,20 +541,24 @@ impl DummyResult { /// /// Use this as a return value after hitting any errors and /// calling `span_err`. - pub fn any(span: Span) -> Box { - Box::new(DummyResult { is_error: true, span }) + pub fn any(span: Span, guar: ErrorGuaranteed) -> Box { + Box::new(DummyResult { guar: Some(guar), span }) } /// Same as `any`, but must be a valid fragment, not error. pub fn any_valid(span: Span) -> Box { - Box::new(DummyResult { is_error: false, span }) + Box::new(DummyResult { guar: None, span }) } /// A plain dummy expression. - pub fn raw_expr(sp: Span, is_error: bool) -> P { + pub fn raw_expr(sp: Span, guar: Option) -> P { P(ast::Expr { id: ast::DUMMY_NODE_ID, - kind: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(ThinVec::new()) }, + kind: if let Some(guar) = guar { + ast::ExprKind::Err(guar) + } else { + ast::ExprKind::Tup(ThinVec::new()) + }, span: sp, attrs: ast::AttrVec::new(), tokens: None, @@ -582,7 +586,7 @@ impl DummyResult { impl MacResult for DummyResult { fn make_expr(self: Box) -> Option> { - Some(DummyResult::raw_expr(self.span, self.is_error)) + Some(DummyResult::raw_expr(self.span, self.guar)) } fn make_pat(self: Box) -> Option> { @@ -608,7 +612,7 @@ impl MacResult for DummyResult { fn make_stmts(self: Box) -> Option> { Some(smallvec![ast::Stmt { id: ast::DUMMY_NODE_ID, - kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), + kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.guar)), span: self.span, }]) } @@ -884,17 +888,19 @@ impl SyntaxExtension { } } + /// A dummy bang macro `foo!()`. pub fn dummy_bang(edition: Edition) -> SyntaxExtension { fn expander<'cx>( - _: &'cx mut ExtCtxt<'_>, + cx: &'cx mut ExtCtxt<'_>, span: Span, _: TokenStream, ) -> Box { - DummyResult::any(span) + DummyResult::any(span, cx.dcx().span_delayed_bug(span, "expanded a dummy bang macro")) } SyntaxExtension::default(SyntaxExtensionKind::LegacyBang(Box::new(expander)), edition) } + /// A dummy derive macro `#[derive(Foo)]`. pub fn dummy_derive(edition: Edition) -> SyntaxExtension { fn expander( _: &mut ExtCtxt<'_>, @@ -1066,7 +1072,7 @@ pub struct ExtCtxt<'a> { pub sess: &'a Session, pub ecfg: expand::ExpansionConfig<'a>, pub num_standard_library_imports: usize, - pub reduced_recursion_limit: Option, + pub reduced_recursion_limit: Option<(Limit, ErrorGuaranteed)>, pub root_path: PathBuf, pub resolver: &'a mut dyn ResolverExpand, pub current_expansion: ExpansionData, @@ -1244,7 +1250,7 @@ pub fn resolve_path( /// Extracts a string literal from the macro expanded version of `expr`, /// returning a diagnostic error of `err_msg` if `expr` is not a string literal. /// The returned bool indicates whether an applicable suggestion has already been -/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)` +/// added to the diagnostic to avoid emitting multiple suggestions. `Err(Err(ErrorGuaranteed))` /// indicates that an ast error was encountered. // FIXME(Nilstrieb) Make this function setup translatable #[allow(rustc::untranslatable_diagnostic)] @@ -1252,7 +1258,10 @@ pub fn expr_to_spanned_string<'a>( cx: &'a mut ExtCtxt<'_>, expr: P, err_msg: &'static str, -) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> { +) -> Result< + (Symbol, ast::StrStyle, Span), + Result<(DiagnosticBuilder<'a>, bool /* has_suggestions */), ErrorGuaranteed>, +> { // Perform eager expansion on the expression. // We want to be able to handle e.g., `concat!("foo", "bar")`. let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr(); @@ -1269,38 +1278,33 @@ pub fn expr_to_spanned_string<'a>( "", Applicability::MaybeIncorrect, ); - Some((err, true)) - } - Ok(ast::LitKind::Err(_)) => None, - Err(err) => { - report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span); - None + Ok((err, true)) } - _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), + Ok(ast::LitKind::Err(guar)) => Err(guar), + Err(err) => Err(report_lit_error(&cx.sess.parse_sess, err, token_lit, expr.span)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), }, - ast::ExprKind::Err => None, + ast::ExprKind::Err(guar) => Err(guar), ast::ExprKind::Dummy => { cx.dcx().span_bug(expr.span, "tried to get a string literal from `ExprKind::Dummy`") } - _ => Some((cx.dcx().struct_span_err(expr.span, err_msg), false)), + _ => Ok((cx.dcx().struct_span_err(expr.span, err_msg), false)), }) } /// Extracts a string literal from the macro expanded version of `expr`, /// emitting `err_msg` if `expr` is not a string literal. This does not stop -/// compilation on error, merely emits a non-fatal error and returns `None`. +/// compilation on error, merely emits a non-fatal error and returns `Err`. pub fn expr_to_string( cx: &mut ExtCtxt<'_>, expr: P, err_msg: &'static str, -) -> Option<(Symbol, ast::StrStyle)> { +) -> Result<(Symbol, ast::StrStyle), ErrorGuaranteed> { expr_to_spanned_string(cx, expr, err_msg) - .map_err(|err| { - err.map(|(err, _)| { - err.emit(); - }) + .map_err(|err| match err { + Ok((err, _)) => err.emit(), + Err(guar) => guar, }) - .ok() .map(|(symbol, style, _)| (symbol, style)) } @@ -1314,32 +1318,30 @@ pub fn check_zero_tts(cx: &ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str } } -/// Parse an expression. On error, emit it, advancing to `Eof`, and return `None`. -pub fn parse_expr(p: &mut parser::Parser<'_>) -> Option> { - match p.parse_expr() { - Ok(e) => return Some(e), - Err(err) => { - err.emit(); - } - } +/// Parse an expression. On error, emit it, advancing to `Eof`, and return `Err`. +pub fn parse_expr(p: &mut parser::Parser<'_>) -> Result, ErrorGuaranteed> { + let guar = match p.parse_expr() { + Ok(expr) => return Ok(expr), + Err(err) => err.emit(), + }; while p.token != token::Eof { p.bump(); } - None + Err(guar) } /// Interpreting `tts` as a comma-separated sequence of expressions, -/// expect exactly one string literal, or emit an error and return `None`. +/// expect exactly one string literal, or emit an error and return `Err`. pub fn get_single_str_from_tts( cx: &mut ExtCtxt<'_>, span: Span, tts: TokenStream, name: &str, -) -> Option { +) -> Result { let mut p = cx.new_parser_from_tts(tts); if p.token == token::Eof { - cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); - return None; + let guar = cx.dcx().emit_err(errors::OnlyOneArgument { span, name }); + return Err(guar); } let ret = parse_expr(&mut p)?; let _ = p.eat(&token::Comma); @@ -1351,8 +1353,11 @@ pub fn get_single_str_from_tts( } /// Extracts comma-separated expressions from `tts`. -/// On error, emit it, and return `None`. -pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option>> { +/// On error, emit it, and return `Err`. +pub fn get_exprs_from_tts( + cx: &mut ExtCtxt<'_>, + tts: TokenStream, +) -> Result>, ErrorGuaranteed> { let mut p = cx.new_parser_from_tts(tts); let mut es = Vec::new(); while p.token != token::Eof { @@ -1367,11 +1372,11 @@ pub fn get_exprs_from_tts(cx: &mut ExtCtxt<'_>, tts: TokenStream) -> Option AstFragment { - self.make_from(DummyResult::any(span)).expect("couldn't create a dummy AST fragment") + pub(crate) fn dummy(self, span: Span, guar: ErrorGuaranteed) -> AstFragment { + self.make_from(DummyResult::any(span, guar)).expect("couldn't create a dummy AST fragment") } pub fn supports_macro_expansion(self) -> SupportsMacroExpansion { @@ -604,14 +604,14 @@ impl<'a, 'b> MacroExpander<'a, 'b> { (fragment, invocations) } - fn error_recursion_limit_reached(&mut self) { + fn error_recursion_limit_reached(&mut self) -> ErrorGuaranteed { let expn_data = self.cx.current_expansion.id.expn_data(); let suggested_limit = match self.cx.ecfg.recursion_limit { Limit(0) => Limit(2), limit => limit * 2, }; - self.cx.dcx().emit_err(RecursionLimitReached { + let guar = self.cx.dcx().emit_err(RecursionLimitReached { span: expn_data.call_site, descr: expn_data.kind.descr(), suggested_limit, @@ -619,14 +619,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }); self.cx.trace_macros_diag(); + guar } /// A macro's expansion does not fit in this fragment kind. /// For example, a non-type macro in a type position. - fn error_wrong_fragment_kind(&mut self, kind: AstFragmentKind, mac: &ast::MacCall, span: Span) { - self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); - + fn error_wrong_fragment_kind( + &mut self, + kind: AstFragmentKind, + mac: &ast::MacCall, + span: Span, + ) -> ErrorGuaranteed { + let guar = + self.cx.dcx().emit_err(WrongFragmentKind { span, kind: kind.name(), name: &mac.path }); self.cx.trace_macros_diag(); + guar } fn expand_invoc( @@ -634,36 +641,41 @@ impl<'a, 'b> MacroExpander<'a, 'b> { invoc: Invocation, ext: &SyntaxExtensionKind, ) -> ExpandResult { - let recursion_limit = - self.cx.reduced_recursion_limit.unwrap_or(self.cx.ecfg.recursion_limit); + let recursion_limit = match self.cx.reduced_recursion_limit { + Some((limit, _)) => limit, + None => self.cx.ecfg.recursion_limit, + }; + if !recursion_limit.value_within_limit(self.cx.current_expansion.depth) { - if self.cx.reduced_recursion_limit.is_none() { - self.error_recursion_limit_reached(); - } + let guar = match self.cx.reduced_recursion_limit { + Some((_, guar)) => guar, + None => self.error_recursion_limit_reached(), + }; // Reduce the recursion limit by half each time it triggers. - self.cx.reduced_recursion_limit = Some(recursion_limit / 2); + self.cx.reduced_recursion_limit = Some((recursion_limit / 2, guar)); - return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span())); + return ExpandResult::Ready(invoc.fragment_kind.dummy(invoc.span(), guar)); } let (fragment_kind, span) = (invoc.fragment_kind, invoc.span()); ExpandResult::Ready(match invoc.kind { InvocationKind::Bang { mac, .. } => match ext { SyntaxExtensionKind::Bang(expander) => { - let Ok(tok_result) = expander.expand(self.cx, span, mac.args.tokens.clone()) - else { - return ExpandResult::Ready(fragment_kind.dummy(span)); - }; - self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + match expander.expand(self.cx, span, mac.args.tokens.clone()) { + Ok(tok_result) => { + self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span) + } + Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), + } } SyntaxExtensionKind::LegacyBang(expander) => { let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone()); let result = if let Some(result) = fragment_kind.make_from(tok_result) { result } else { - self.error_wrong_fragment_kind(fragment_kind, &mac, span); - fragment_kind.dummy(span) + let guar = self.error_wrong_fragment_kind(fragment_kind, &mac, span); + fragment_kind.dummy(span, guar) }; result } @@ -705,11 +717,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { self.cx.dcx().emit_err(UnsupportedKeyValue { span }); } let inner_tokens = attr_item.args.inner_tokens(); - let Ok(tok_result) = expander.expand(self.cx, span, inner_tokens, tokens) - else { - return ExpandResult::Ready(fragment_kind.dummy(span)); - }; - self.parse_ast_fragment(tok_result, fragment_kind, &attr_item.path, span) + match expander.expand(self.cx, span, inner_tokens, tokens) { + Ok(tok_result) => self.parse_ast_fragment( + tok_result, + fragment_kind, + &attr_item.path, + span, + ), + Err(guar) => return ExpandResult::Ready(fragment_kind.dummy(span, guar)), + } } SyntaxExtensionKind::LegacyAttr(expander) => { match validate_attr::parse_meta(&self.cx.sess.parse_sess, &attr) { @@ -729,15 +745,15 @@ impl<'a, 'b> MacroExpander<'a, 'b> { AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr ) && items.is_empty() { - self.cx.dcx().emit_err(RemoveExprNotSupported { span }); - fragment_kind.dummy(span) + let guar = self.cx.dcx().emit_err(RemoveExprNotSupported { span }); + fragment_kind.dummy(span, guar) } else { fragment_kind.expect_from_annotatables(items) } } Err(err) => { - err.emit(); - fragment_kind.dummy(span) + let guar = err.emit(); + fragment_kind.dummy(span, guar) } } } @@ -857,9 +873,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { err.span(span); } annotate_err_with_kind(&mut err, kind, span); - err.emit(); + let guar = err.emit(); self.cx.trace_macros_diag(); - kind.dummy(span) + kind.dummy(span, guar) } } } diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs index 25af974d3266c..5629c5ef5fa06 100644 --- a/compiler/rustc_expand/src/mbe/diagnostics.rs +++ b/compiler/rustc_expand/src/mbe/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_errors::{Applicability, DiagCtxt, DiagnosticBuilder, DiagnosticMessage use rustc_parse::parser::{Parser, Recovery}; use rustc_span::source_map::SourceMap; use rustc_span::symbol::Ident; -use rustc_span::Span; +use rustc_span::{ErrorGuaranteed, Span}; use std::borrow::Cow; use super::macro_rules::{parser_from_cx, NoopTracker}; @@ -47,7 +47,7 @@ pub(super) fn failed_to_match_macro<'cx>( let Some(BestFailure { token, msg: label, remaining_matcher, .. }) = tracker.best_failure else { - return DummyResult::any(sp); + return DummyResult::any(sp, cx.dcx().span_delayed_bug(sp, "failed to match a macro")); }; let span = token.span.substitute_dummy(sp); @@ -106,9 +106,9 @@ pub(super) fn failed_to_match_macro<'cx>( } } } - err.emit(); + let guar = err.emit(); cx.trace_macros_diag(); - DummyResult::any(sp) + DummyResult::any(sp, guar) } /// The tracker used for the slow error path that collects useful info for diagnostics. @@ -180,10 +180,10 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx, } Error(err_sp, msg) => { let span = err_sp.substitute_dummy(self.root_span); - self.cx.dcx().span_err(span, msg.clone()); - self.result = Some(DummyResult::any(span)); + let guar = self.cx.dcx().span_err(span, msg.clone()); + self.result = Some(DummyResult::any(span, guar)); } - ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)), + ErrorReported(guar) => self.result = Some(DummyResult::any(self.root_span, *guar)), } } @@ -224,7 +224,7 @@ pub(super) fn emit_frag_parse_err( site_span: Span, arm_span: Span, kind: AstFragmentKind, -) { +) -> ErrorGuaranteed { // FIXME(davidtwco): avoid depending on the error message text if parser.token == token::Eof && let DiagnosticMessage::Str(message) = &e.messages[0].0 @@ -282,7 +282,7 @@ pub(super) fn emit_frag_parse_err( }, _ => annotate_err_with_kind(&mut e, kind, site_span), }; - e.emit(); + e.emit() } pub(crate) fn annotate_err_with_kind( diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs index ffc8f782fd344..8174cb03d337b 100644 --- a/compiler/rustc_expand/src/mbe/macro_check.rs +++ b/compiler/rustc_expand/src/mbe/macro_check.rs @@ -114,7 +114,7 @@ use rustc_errors::{DiagnosticMessage, MultiSpan}; use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER}; use rustc_session::parse::ParseSess; use rustc_span::symbol::kw; -use rustc_span::{symbol::MacroRulesNormalizedIdent, Span}; +use rustc_span::{symbol::MacroRulesNormalizedIdent, ErrorGuaranteed, Span}; use smallvec::SmallVec; @@ -203,17 +203,17 @@ pub(super) fn check_meta_variables( span: Span, lhses: &[TokenTree], rhses: &[TokenTree], -) -> bool { +) -> Result<(), ErrorGuaranteed> { if lhses.len() != rhses.len() { sess.dcx.span_bug(span, "length mismatch between LHSes and RHSes") } - let mut valid = true; + let mut guar = None; for (lhs, rhs) in iter::zip(lhses, rhses) { let mut binders = Binders::default(); - check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut valid); - check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut valid); + check_binders(sess, node_id, lhs, &Stack::Empty, &mut binders, &Stack::Empty, &mut guar); + check_occurrences(sess, node_id, rhs, &Stack::Empty, &binders, &Stack::Empty, &mut guar); } - valid + guar.map_or(Ok(()), Err) } /// Checks `lhs` as part of the LHS of a macro definition, extends `binders` with new binders, and @@ -226,7 +226,7 @@ pub(super) fn check_meta_variables( /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the LHS /// - `ops` is the stack of Kleene operators from the LHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_binders( sess: &ParseSess, node_id: NodeId, @@ -234,7 +234,7 @@ fn check_binders( macros: &Stack<'_, MacroState<'_>>, binders: &mut Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { match *lhs { TokenTree::Token(..) => {} @@ -258,7 +258,7 @@ fn check_binders( binders.insert(name, BinderInfo { span, ops: ops.into() }); } else { // 3. The meta-variable is bound: This is an occurrence. - check_occurrences(sess, node_id, lhs, macros, binders, ops, valid); + check_occurrences(sess, node_id, lhs, macros, binders, ops, guar); } } // Similarly, this can only happen when checking a toplevel macro. @@ -281,8 +281,10 @@ fn check_binders( 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.dcx.emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }); - *valid = false; + *guar = Some( + sess.dcx + .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span }), + ); } else { binders.insert(name, BinderInfo { span, ops: ops.into() }); } @@ -291,13 +293,13 @@ fn check_binders( TokenTree::MetaVarExpr(..) => {} TokenTree::Delimited(.., ref del) => { for tt in &del.tts { - check_binders(sess, node_id, tt, macros, binders, ops, valid); + check_binders(sess, node_id, tt, macros, binders, ops, guar); } } TokenTree::Sequence(_, ref seq) => { let ops = ops.push(seq.kleene); for tt in &seq.tts { - check_binders(sess, node_id, tt, macros, binders, &ops, valid); + check_binders(sess, node_id, tt, macros, binders, &ops, guar); } } } @@ -327,7 +329,7 @@ fn get_binder_info<'a>( /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the associated LHS /// - `ops` is the stack of Kleene operators from the RHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_occurrences( sess: &ParseSess, node_id: NodeId, @@ -335,7 +337,7 @@ fn check_occurrences( macros: &Stack<'_, MacroState<'_>>, binders: &Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { match *rhs { TokenTree::Token(..) => {} @@ -353,11 +355,11 @@ fn check_occurrences( check_ops_is_prefix(sess, node_id, macros, binders, ops, dl.entire(), name); } TokenTree::Delimited(.., ref del) => { - check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, valid); + check_nested_occurrences(sess, node_id, &del.tts, macros, binders, ops, guar); } TokenTree::Sequence(_, ref seq) => { let ops = ops.push(seq.kleene); - check_nested_occurrences(sess, node_id, &seq.tts, macros, binders, &ops, valid); + check_nested_occurrences(sess, node_id, &seq.tts, macros, binders, &ops, guar); } } } @@ -392,7 +394,7 @@ enum NestedMacroState { /// - `macros` is the stack of possible outer macros /// - `binders` contains the binders of the associated LHS /// - `ops` is the stack of Kleene operators from the RHS -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_nested_occurrences( sess: &ParseSess, node_id: NodeId, @@ -400,7 +402,7 @@ fn check_nested_occurrences( macros: &Stack<'_, MacroState<'_>>, binders: &Binders, ops: &Stack<'_, KleeneToken>, - valid: &mut bool, + guar: &mut Option, ) { let mut state = NestedMacroState::Empty; let nested_macros = macros.push(MacroState { binders, ops: ops.into() }); @@ -432,7 +434,7 @@ fn check_nested_occurrences( (NestedMacroState::MacroRulesNot, &TokenTree::MetaVar(..)) => { state = NestedMacroState::MacroRulesNotName; // We check that the meta-variable is correctly used. - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } (NestedMacroState::MacroRulesNotName, TokenTree::Delimited(.., del)) | (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) @@ -441,7 +443,7 @@ fn check_nested_occurrences( let macro_rules = state == NestedMacroState::MacroRulesNotName; state = NestedMacroState::Empty; let rest = - check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, valid); + check_nested_macro(sess, node_id, macro_rules, &del.tts, &nested_macros, guar); // If we did not check the whole macro definition, then check the rest as if outside // the macro definition. check_nested_occurrences( @@ -451,7 +453,7 @@ fn check_nested_occurrences( macros, binders, ops, - valid, + guar, ); } ( @@ -463,7 +465,7 @@ fn check_nested_occurrences( (NestedMacroState::Macro, &TokenTree::MetaVar(..)) => { state = NestedMacroState::MacroName; // We check that the meta-variable is correctly used. - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } (NestedMacroState::MacroName, TokenTree::Delimited(.., del)) if del.delim == Delimiter::Parenthesis => @@ -477,7 +479,7 @@ fn check_nested_occurrences( &nested_macros, &mut nested_binders, &Stack::Empty, - valid, + guar, ); } (NestedMacroState::MacroNameParen, TokenTree::Delimited(.., del)) @@ -491,12 +493,12 @@ fn check_nested_occurrences( &nested_macros, &nested_binders, &Stack::Empty, - valid, + guar, ); } (_, tt) => { state = NestedMacroState::Empty; - check_occurrences(sess, node_id, tt, macros, binders, ops, valid); + check_occurrences(sess, node_id, tt, macros, binders, ops, guar); } } } @@ -515,14 +517,14 @@ fn check_nested_occurrences( /// - `macro_rules` specifies whether the macro is `macro_rules` /// - `tts` is checked as a list of (LHS) => {RHS} /// - `macros` is the stack of outer macros -/// - `valid` is set in case of errors +/// - `guar` is set in case of errors fn check_nested_macro( sess: &ParseSess, node_id: NodeId, macro_rules: bool, tts: &[TokenTree], macros: &Stack<'_, MacroState<'_>>, - valid: &mut bool, + guar: &mut Option, ) -> usize { let n = tts.len(); let mut i = 0; @@ -539,8 +541,8 @@ fn check_nested_macro( let lhs = &tts[i]; let rhs = &tts[i + 2]; let mut binders = Binders::default(); - check_binders(sess, node_id, lhs, macros, &mut binders, &Stack::Empty, valid); - check_occurrences(sess, node_id, rhs, macros, &binders, &Stack::Empty, valid); + check_binders(sess, node_id, lhs, macros, &mut binders, &Stack::Empty, guar); + check_occurrences(sess, node_id, rhs, macros, &binders, &Stack::Empty, guar); // Since the last semicolon is optional for `macro_rules` macros and decl_macro are not terminated, // we increment our checked position by how many token trees we already checked (the 3 // above) before checking for the separator. diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index bf99e9e6d5cc8..c11d538048aa9 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -66,8 +66,10 @@ impl<'a> ParserAnyMacro<'a> { let fragment = match parse_ast_fragment(parser, kind) { Ok(f) => f, Err(err) => { - diagnostics::emit_frag_parse_err(err, parser, snapshot, site_span, arm_span, kind); - return kind.dummy(site_span); + let guar = diagnostics::emit_frag_parse_err( + err, parser, snapshot, site_span, arm_span, kind, + ); + return kind.dummy(site_span, guar); } }; @@ -101,7 +103,6 @@ struct MacroRulesMacroExpander { transparency: Transparency, lhses: Vec>, rhses: Vec, - valid: bool, } impl TTMacroExpander for MacroRulesMacroExpander { @@ -111,9 +112,6 @@ impl TTMacroExpander for MacroRulesMacroExpander { sp: Span, input: TokenStream, ) -> Box { - if !self.valid { - return DummyResult::any(sp); - } expand_macro( cx, sp, @@ -128,12 +126,17 @@ impl TTMacroExpander for MacroRulesMacroExpander { } } -fn macro_rules_dummy_expander<'cx>( - _: &'cx mut ExtCtxt<'_>, - span: Span, - _: TokenStream, -) -> Box { - DummyResult::any(span) +struct DummyExpander(ErrorGuaranteed); + +impl TTMacroExpander for DummyExpander { + fn expand<'cx>( + &self, + _: &'cx mut ExtCtxt<'_>, + span: Span, + _: TokenStream, + ) -> Box { + DummyResult::any(span, self.0) + } } fn trace_macros_note(cx_expansions: &mut FxIndexMap>, sp: Span, message: String) { @@ -217,8 +220,8 @@ fn expand_macro<'cx>( let tts = match transcribe(cx, &named_matches, rhs, rhs_span, transparency) { Ok(tts) => tts, Err(err) => { - err.emit(); - return DummyResult::any(arm_span); + let guar = err.emit(); + return DummyResult::any(arm_span, guar); } }; @@ -249,9 +252,9 @@ fn expand_macro<'cx>( is_local, }) } - Err(CanRetry::No(_)) => { + Err(CanRetry::No(guar)) => { debug!("Will not retry matching as an error was emitted already"); - DummyResult::any(sp) + DummyResult::any(sp, guar) } Err(CanRetry::Yes) => { // Retry and emit a better error. @@ -371,7 +374,7 @@ pub fn compile_declarative_macro( def.id != DUMMY_NODE_ID, ) }; - let dummy_syn_ext = || (mk_syn_ext(Box::new(macro_rules_dummy_expander)), Vec::new()); + let dummy_syn_ext = |guar| (mk_syn_ext(Box::new(DummyExpander(guar))), Vec::new()); let dcx = &sess.parse_sess.dcx; let lhs_nm = Ident::new(sym::lhs, def.span); @@ -456,19 +459,20 @@ pub fn compile_declarative_macro( let mut err = sess.dcx().struct_span_err(sp, s); err.span_label(sp, msg); annotate_doc_comment(sess.dcx(), &mut err, sess.source_map(), sp); - err.emit(); - return dummy_syn_ext(); + let guar = err.emit(); + return dummy_syn_ext(guar); } Error(sp, msg) => { - sess.dcx().span_err(sp.substitute_dummy(def.span), msg); - return dummy_syn_ext(); + let guar = sess.dcx().span_err(sp.substitute_dummy(def.span), msg); + return dummy_syn_ext(guar); } - ErrorReported(_) => { - return dummy_syn_ext(); + ErrorReported(guar) => { + return dummy_syn_ext(guar); } }; - let mut valid = true; + let mut guar = None; + let mut check_emission = |ret: Result<(), ErrorGuaranteed>| guar = guar.or(ret.err()); // Extract the arguments: let lhses = match &argument_map[&MacroRulesNormalizedIdent::new(lhs_nm)] { @@ -488,7 +492,7 @@ pub fn compile_declarative_macro( .unwrap(); // We don't handle errors here, the driver will abort // after parsing/expansion. we can report every error in every macro this way. - valid &= check_lhs_nt_follows(sess, def, &tt).is_ok(); + check_emission(check_lhs_nt_follows(sess, def, &tt)); return tt; } sess.dcx().span_bug(def.span, "wrong-structured lhs") @@ -520,15 +524,21 @@ pub fn compile_declarative_macro( }; for rhs in &rhses { - valid &= check_rhs(sess, rhs); + check_emission(check_rhs(sess, rhs)); } // don't abort iteration early, so that errors for multiple lhses can be reported for lhs in &lhses { - valid &= check_lhs_no_empty_seq(sess, slice::from_ref(lhs)); + check_emission(check_lhs_no_empty_seq(sess, slice::from_ref(lhs))); } - valid &= macro_check::check_meta_variables(&sess.parse_sess, def.id, def.span, &lhses, &rhses); + check_emission(macro_check::check_meta_variables( + &sess.parse_sess, + def.id, + def.span, + &lhses, + &rhses, + )); let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules); match transparency_error { @@ -541,11 +551,15 @@ pub fn compile_declarative_macro( None => {} } + if let Some(guar) = guar { + // To avoid warning noise, only consider the rules of this + // macro for the lint, if all rules are valid. + return dummy_syn_ext(guar); + } + // Compute the spans of the macro rules for unused rule linting. - // To avoid warning noise, only consider the rules of this - // macro for the lint, if all rules are valid. // Also, we are only interested in non-foreign macros. - let rule_spans = if valid && def.id != DUMMY_NODE_ID { + let rule_spans = if def.id != DUMMY_NODE_ID { lhses .iter() .zip(rhses.iter()) @@ -562,23 +576,19 @@ pub fn compile_declarative_macro( }; // Convert the lhses into `MatcherLoc` form, which is better for doing the - // actual matching. Unless the matcher is invalid. - let lhses = if valid { - lhses - .iter() - .map(|lhs| { - // Ignore the delimiters around the matcher. - match lhs { - mbe::TokenTree::Delimited(.., delimited) => { - mbe::macro_parser::compute_locs(&delimited.tts) - } - _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + // actual matching. + let lhses = lhses + .iter() + .map(|lhs| { + // Ignore the delimiters around the matcher. + match lhs { + mbe::TokenTree::Delimited(.., delimited) => { + mbe::macro_parser::compute_locs(&delimited.tts) } - }) - .collect() - } else { - vec![] - }; + _ => sess.dcx().span_bug(def.span, "malformed macro lhs"), + } + }) + .collect(); let expander = Box::new(MacroRulesMacroExpander { name: def.ident, @@ -587,7 +597,6 @@ pub fn compile_declarative_macro( transparency, lhses, rhses, - valid, }); (mk_syn_ext(expander), rule_spans) } @@ -640,7 +649,7 @@ fn is_empty_token_tree(sess: &Session, seq: &mbe::SequenceRepetition) -> bool { /// Checks that the lhs contains no repetition which could match an empty token /// tree, because then the matcher would hang indefinitely. -fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> bool { +fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> Result<(), ErrorGuaranteed> { use mbe::TokenTree; for tt in tts { match tt { @@ -648,35 +657,26 @@ fn check_lhs_no_empty_seq(sess: &Session, tts: &[mbe::TokenTree]) -> bool { | TokenTree::MetaVar(..) | TokenTree::MetaVarDecl(..) | TokenTree::MetaVarExpr(..) => (), - TokenTree::Delimited(.., del) => { - if !check_lhs_no_empty_seq(sess, &del.tts) { - return false; - } - } + TokenTree::Delimited(.., del) => check_lhs_no_empty_seq(sess, &del.tts)?, TokenTree::Sequence(span, seq) => { if is_empty_token_tree(sess, seq) { let sp = span.entire(); - sess.dcx().span_err(sp, "repetition matches empty token tree"); - return false; - } - if !check_lhs_no_empty_seq(sess, &seq.tts) { - return false; + let guar = sess.dcx().span_err(sp, "repetition matches empty token tree"); + return Err(guar); } + check_lhs_no_empty_seq(sess, &seq.tts)? } } } - true + Ok(()) } -fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> bool { +fn check_rhs(sess: &Session, rhs: &mbe::TokenTree) -> Result<(), ErrorGuaranteed> { match *rhs { - mbe::TokenTree::Delimited(..) => return true, - _ => { - sess.dcx().span_err(rhs.span(), "macro rhs must be delimited"); - } + mbe::TokenTree::Delimited(..) => Ok(()), + _ => Err(sess.dcx().span_err(rhs.span(), "macro rhs must be delimited")), } - false } fn check_matcher( diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 35ee0c530463b..3481c66da702e 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -758,7 +758,7 @@ trait UnusedDelimLint { } impl<'ast> Visitor<'ast> for ErrExprVisitor { fn visit_expr(&mut self, expr: &'ast ast::Expr) { - if let ExprKind::Err = expr.kind { + if let ExprKind::Err(_) = expr.kind { self.has_error = true; return; } diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 517e3d827876b..cc1f7c8ac7d58 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -744,7 +744,8 @@ impl<'a> Parser<'a> { Err(err) } - pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) { + /// The user has written `#[attr] expr` which is unsupported. (#106020) + pub(super) fn attr_on_non_tail_expr(&self, expr: &Expr) -> ErrorGuaranteed { // Missing semicolon typo error. let span = self.prev_token.span.shrink_to_hi(); let mut err = self.dcx().create_err(ExpectedSemi { @@ -787,6 +788,8 @@ impl<'a> Parser<'a> { ], Applicability::MachineApplicable, ); + + // Special handling for `#[cfg(...)]` chains let mut snapshot = self.create_snapshot_for_diagnostic(); if let [attr] = &expr.attrs[..] && let ast::AttrKind::Normal(attr_kind) = &attr.kind @@ -799,7 +802,7 @@ impl<'a> Parser<'a> { Err(inner_err) => { err.cancel(); inner_err.cancel(); - return; + return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); } } && let ast::AttrKind::Normal(next_attr_kind) = next_attr.kind @@ -812,7 +815,7 @@ impl<'a> Parser<'a> { Err(inner_err) => { err.cancel(); inner_err.cancel(); - return; + return self.dcx().span_delayed_bug(expr.span, "not a tail expression"); } }; // We have for sure @@ -845,7 +848,7 @@ impl<'a> Parser<'a> { ); } } - err.emit(); + err.emit() } fn check_too_many_raw_str_terminators(&mut self, err: &mut DiagnosticBuilder<'_>) -> bool { @@ -921,10 +924,10 @@ impl<'a> Parser<'a> { // fn foo() -> Foo { Path { // field: value, // } } - err.delay_as_bug(); + let guar = err.delay_as_bug(); self.restore_snapshot(snapshot); let mut tail = self.mk_block( - thin_vec![self.mk_stmt_err(expr.span)], + thin_vec![self.mk_stmt_err(expr.span, guar)], s, lo.to(self.prev_token.span), ); @@ -990,7 +993,7 @@ impl<'a> Parser<'a> { decl_hi: Span, ) -> PResult<'a, P> { err.span_label(lo.to(decl_hi), "while parsing the body of this closure"); - match before.kind { + let guar = match before.kind { token::OpenDelim(Delimiter::Brace) if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { @@ -1004,8 +1007,9 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - err.emit(); + let guar = err.emit(); self.eat_to_tokens(&[&token::CloseDelim(Delimiter::Brace)]); + guar } token::OpenDelim(Delimiter::Parenthesis) if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => @@ -1022,7 +1026,7 @@ impl<'a> Parser<'a> { ], Applicability::MaybeIncorrect, ); - err.emit(); + err.emit() } _ if !matches!(token.kind, token::OpenDelim(Delimiter::Brace)) => { // We don't have a heuristic to correctly identify where the block @@ -1035,8 +1039,8 @@ impl<'a> Parser<'a> { return Err(err); } _ => return Err(err), - } - Ok(self.mk_expr_err(lo.to(self.token.span))) + }; + Ok(self.mk_expr_err(lo.to(self.token.span), guar)) } /// Eats and discards tokens until one of `kets` is encountered. Respects token trees, @@ -1214,7 +1218,7 @@ impl<'a> Parser<'a> { &mut self, mut e: DiagnosticBuilder<'a>, expr: &mut P, - ) -> PResult<'a, ()> { + ) -> PResult<'a, ErrorGuaranteed> { if let ExprKind::Binary(binop, _, _) = &expr.kind && let ast::BinOpKind::Lt = binop.node && self.eat(&token::Comma) @@ -1239,9 +1243,9 @@ impl<'a> Parser<'a> { // The subsequent expression is valid. Mark // `expr` as erroneous and emit `e` now, but // return `Ok` so parsing can continue. - e.emit(); - *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); - return Ok(()); + let guar = e.emit(); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span), guar); + return Ok(guar); } Err(err) => { err.cancel(); @@ -1393,7 +1397,8 @@ impl<'a> Parser<'a> { outer_op.node, ); - let mk_err_expr = |this: &Self, span| Ok(Some(this.mk_expr(span, ExprKind::Err))); + let mk_err_expr = + |this: &Self, span, guar| Ok(Some(this.mk_expr(span, ExprKind::Err(guar)))); match &inner_op.kind { ExprKind::Binary(op, l1, r1) if op.node.is_comparison() => { @@ -1443,11 +1448,11 @@ impl<'a> Parser<'a> { match self.parse_expr() { Ok(_) => { // 99% certain that the suggestion is correct, continue parsing. - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } Err(expr_err) => { expr_err.cancel(); @@ -1471,11 +1476,11 @@ impl<'a> Parser<'a> { match self.consume_fn_args() { Err(()) => Err(self.dcx().create_err(err)), Ok(()) => { - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); // FIXME: actually check that the two expressions in the binop are // paths and resynthesize new fn call expression instead of using // `ExprKind::Err` placeholder. - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } } } else { @@ -1492,8 +1497,8 @@ impl<'a> Parser<'a> { let recovered = self .attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); if matches!(recovered, Recovered::Yes) { - self.dcx().emit_err(err); - mk_err_expr(self, inner_op.span.to(self.prev_token.span)) + let guar = self.dcx().emit_err(err); + mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar) } else { // These cases cause too many knock-down errors, bail out (#61329). Err(self.dcx().create_err(err)) @@ -1502,9 +1507,9 @@ impl<'a> Parser<'a> { } let recover = self.attempt_chained_comparison_suggestion(&mut err, inner_op, outer_op); - self.dcx().emit_err(err); + let guar = self.dcx().emit_err(err); if matches!(recover, Recovered::Yes) { - return mk_err_expr(self, inner_op.span.to(self.prev_token.span)); + return mk_err_expr(self, inner_op.span.to(self.prev_token.span), guar); } } _ => {} @@ -1925,8 +1930,8 @@ impl<'a> Parser<'a> { } else { self.recover_await_prefix(await_sp)? }; - let sp = self.error_on_incorrect_await(lo, hi, &expr, is_question); - let expr = self.mk_expr(lo.to(sp), ExprKind::Err); + let (sp, guar) = self.error_on_incorrect_await(lo, hi, &expr, is_question); + let expr = self.mk_expr_err(lo.to(sp), guar); self.maybe_recover_from_bad_qpath(expr) } @@ -1955,21 +1960,27 @@ impl<'a> Parser<'a> { Ok((expr.span, expr, is_question)) } - fn error_on_incorrect_await(&self, lo: Span, hi: Span, expr: &Expr, is_question: bool) -> Span { + fn error_on_incorrect_await( + &self, + lo: Span, + hi: Span, + expr: &Expr, + is_question: bool, + ) -> (Span, ErrorGuaranteed) { let span = lo.to(hi); let applicability = match expr.kind { ExprKind::Try(_) => Applicability::MaybeIncorrect, // `await ?` _ => Applicability::MachineApplicable, }; - self.dcx().emit_err(IncorrectAwait { + let guar = self.dcx().emit_err(IncorrectAwait { span, sugg_span: (span, applicability), expr: self.span_to_snippet(expr.span).unwrap_or_else(|_| pprust::expr_to_string(expr)), question_mark: if is_question { "?" } else { "" }, }); - span + (span, guar) } /// If encountering `future.await()`, consumes and emits an error. @@ -2013,8 +2024,8 @@ impl<'a> Parser<'a> { ); } err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable); - err.emit(); - Ok(self.mk_expr_err(lo.to(hi))) + let guar = err.emit(); + Ok(self.mk_expr_err(lo.to(hi), guar)) } else { Err(self.expected_expression_found()) // The user isn't trying to invoke the try! macro } @@ -2059,10 +2070,10 @@ impl<'a> Parser<'a> { lo: Span, err: PErr<'a>, ) -> P { - err.emit(); + let guar = err.emit(); // Recover from parse error, callers expect the closing delim to be consumed. self.consume_block(delim, ConsumeClosingDelim::Yes); - self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err) + self.mk_expr(lo.to(self.prev_token.span), ExprKind::Err(guar)) } /// Eats tokens until we can be relatively sure we reached the end of the @@ -2549,9 +2560,10 @@ impl<'a> Parser<'a> { } _ => None, }; - self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); + let guar = + self.dcx().emit_err(UnexpectedConstParamDeclaration { span: param.span(), sugg }); - let value = self.mk_expr_err(param.span()); + let value = self.mk_expr_err(param.span(), guar); Some(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })) } @@ -2630,8 +2642,8 @@ impl<'a> Parser<'a> { "=", Applicability::MaybeIncorrect, ); - let value = self.mk_expr_err(start.to(expr.span)); - err.emit(); + let guar = err.emit(); + let value = self.mk_expr_err(start.to(expr.span), guar); return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } else if token::Colon == snapshot.token.kind && expr.span.lo() == snapshot.token.span.hi() @@ -2701,8 +2713,8 @@ impl<'a> Parser<'a> { vec![(span.shrink_to_lo(), "{ ".to_string()), (span.shrink_to_hi(), " }".to_string())], Applicability::MaybeIncorrect, ); - let value = self.mk_expr_err(span); - err.emit(); + let guar = err.emit(); + let value = self.mk_expr_err(span, guar); GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value }) } diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 89f28777bffb9..e1a5e17004f6a 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -34,7 +34,7 @@ use rustc_session::lint::builtin::BREAK_WITH_LABEL_AND_LOOP; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_span::source_map::{self, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_span::{BytePos, Pos, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Pos, Span}; use thin_vec::{thin_vec, ThinVec}; /// Possibly accepts an `token::Interpolated` expression (a pre-parsed expression @@ -131,9 +131,9 @@ impl<'a> Parser<'a> { if self.may_recover() && self.look_ahead(1, |t| t == &token::Comma) => { // Special-case handling of `foo(_, _, _)` - err.emit(); + let guar = err.emit(); self.bump(); - Ok(self.mk_expr(self.prev_token.span, ExprKind::Err)) + Ok(self.mk_expr(self.prev_token.span, ExprKind::Err(guar))) } _ => Err(err), }, @@ -667,8 +667,8 @@ impl<'a> Parser<'a> { let (span, _) = self.parse_expr_prefix_common(box_kw)?; let inner_span = span.with_lo(box_kw.hi()); let code = self.sess.source_map().span_to_snippet(inner_span).unwrap(); - self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() }); - Ok((span, ExprKind::Err)) + let guar = self.dcx().emit_err(errors::BoxSyntaxRemoved { span: span, code: code.trim() }); + Ok((span, ExprKind::Err(guar))) } fn is_mistaken_not_ident_negation(&self) -> bool { @@ -860,7 +860,7 @@ impl<'a> Parser<'a> { ExprKind::MethodCall(_) => "a method call", ExprKind::Call(_, _) => "a function call", ExprKind::Await(_, _) => "`.await`", - ExprKind::Err => return Ok(with_postfix), + ExprKind::Err(_) => return Ok(with_postfix), _ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"), } ); @@ -1315,7 +1315,7 @@ impl<'a> Parser<'a> { let fields: Vec<_> = fields.into_iter().filter(|field| !field.is_shorthand).collect(); - if !fields.is_empty() && + let guar = if !fields.is_empty() && // `token.kind` should not be compared here. // This is because the `snapshot.token.kind` is treated as the same as // that of the open delim in `TokenTreesReader::parse_token_tree`, even @@ -1338,11 +1338,11 @@ impl<'a> Parser<'a> { .collect(), }, }) - .emit(); + .emit() } else { - err.emit(); - } - Ok(self.mk_expr_err(span)) + err.emit() + }; + Ok(self.mk_expr_err(span, guar)) } Ok(_) => Err(err), Err(err2) => { @@ -1684,13 +1684,13 @@ impl<'a> Parser<'a> { && (self.check_noexpect(&TokenKind::Comma) || self.check_noexpect(&TokenKind::Gt)) { // We're probably inside of a `Path<'a>` that needs a turbofish - self.dcx().emit_err(errors::UnexpectedTokenAfterLabel { + let guar = self.dcx().emit_err(errors::UnexpectedTokenAfterLabel { span: self.token.span, remove_label: None, enclose_in_block: None, }); consume_colon = false; - Ok(self.mk_expr_err(lo)) + Ok(self.mk_expr_err(lo, guar)) } else { let mut err = errors::UnexpectedTokenAfterLabel { span: self.token.span, @@ -2039,7 +2039,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, L> { if let token::Interpolated(nt) = &self.token.kind && let token::NtExpr(e) | token::NtLiteral(e) = &nt.0 - && matches!(e.kind, ExprKind::Err) + && matches!(e.kind, ExprKind::Err(_)) { let mut err = self .dcx() @@ -2207,7 +2207,7 @@ impl<'a> Parser<'a> { let mut snapshot = self.create_snapshot_for_diagnostic(); match snapshot.parse_expr_array_or_repeat(Delimiter::Brace) { Ok(arr) => { - self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { + let guar = self.dcx().emit_err(errors::ArrayBracketsInsteadOfSpaces { span: arr.span, sub: errors::ArrayBracketsInsteadOfSpacesSugg { left: lo, @@ -2216,7 +2216,7 @@ impl<'a> Parser<'a> { }); self.restore_snapshot(snapshot); - Some(self.mk_expr_err(arr.span)) + Some(self.mk_expr_err(arr.span, guar)) } Err(e) => { e.cancel(); @@ -2370,7 +2370,10 @@ impl<'a> Parser<'a> { // It is likely that the closure body is a block but where the // braces have been removed. We will recover and eat the next // statements later in the parsing process. - body = self.mk_expr_err(body.span); + body = self.mk_expr_err( + body.span, + self.dcx().span_delayed_bug(body.span, "recovered a closure body as a block"), + ); } let body_span = body.span; @@ -2485,7 +2488,7 @@ impl<'a> Parser<'a> { ExprKind::Binary(Spanned { span: binop_span, .. }, _, right) if let ExprKind::Block(_, None) = right.kind => { - this.dcx().emit_err(errors::IfExpressionMissingThenBlock { + let guar = this.dcx().emit_err(errors::IfExpressionMissingThenBlock { if_span: lo, missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::UnfinishedCondition( @@ -2493,14 +2496,14 @@ impl<'a> Parser<'a> { ), let_else_sub: None, }); - std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi())) + std::mem::replace(right, this.mk_expr_err(binop_span.shrink_to_hi(), guar)) } ExprKind::Block(_, None) => { - this.dcx().emit_err(errors::IfExpressionMissingCondition { + let guar = this.dcx().emit_err(errors::IfExpressionMissingCondition { if_span: lo.with_neighbor(cond.span).shrink_to_hi(), block_span: self.sess.source_map().start_point(cond_span), }); - std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi())) + std::mem::replace(&mut cond, this.mk_expr_err(cond_span.shrink_to_hi(), guar)) } _ => { return None; @@ -2520,14 +2523,14 @@ impl<'a> Parser<'a> { let let_else_sub = matches!(cond.kind, ExprKind::Let(..)) .then(|| errors::IfExpressionLetSomeSub { if_span: lo.until(cond_span) }); - self.dcx().emit_err(errors::IfExpressionMissingThenBlock { + let guar = self.dcx().emit_err(errors::IfExpressionMissingThenBlock { if_span: lo, missing_then_block_sub: errors::IfExpressionMissingThenBlockSub::AddThenBlock( cond_span.shrink_to_hi(), ), let_else_sub, }); - self.mk_block_err(cond_span.shrink_to_hi()) + self.mk_block_err(cond_span.shrink_to_hi(), guar) } } else { let attrs = self.parse_outer_attributes()?; // For recovery. @@ -2797,9 +2800,10 @@ impl<'a> Parser<'a> { && !matches!(self.token.kind, token::OpenDelim(Delimiter::Brace)) && self.may_recover() { - self.dcx() + let guar = self + .dcx() .emit_err(errors::MissingExpressionInForLoop { span: expr.span.shrink_to_lo() }); - let err_expr = self.mk_expr(expr.span, ExprKind::Err); + let err_expr = self.mk_expr(expr.span, ExprKind::Err(guar)); let block = self.mk_block(thin_vec![], BlockCheckMode::Default, self.prev_token.span); return Ok(self.mk_expr( lo.to(self.prev_token.span), @@ -2924,7 +2928,7 @@ impl<'a> Parser<'a> { attrs: Default::default(), pat: self.mk_pat(span, ast::PatKind::Err(guar)), guard: None, - body: Some(self.mk_expr_err(span)), + body: Some(self.mk_expr_err(span, guar)), span, id: DUMMY_NODE_ID, is_placeholder: false, @@ -2959,7 +2963,7 @@ impl<'a> Parser<'a> { let err = |this: &Parser<'_>, stmts: Vec| { let span = stmts[0].span.to(stmts[stmts.len() - 1].span); - this.dcx().emit_err(errors::MatchArmBodyWithoutBraces { + let guar = this.dcx().emit_err(errors::MatchArmBodyWithoutBraces { statements: span, arrow: arrow_span, num_statements: stmts.len(), @@ -2972,7 +2976,7 @@ impl<'a> Parser<'a> { errors::MatchArmBodyWithoutBracesSugg::UseComma { semicolon: semi_sp } }, }); - this.mk_expr_err(span) + this.mk_expr_err(span, guar) }; // We might have either a `,` -> `;` typo, or a block without braces. We need // a more subtle parsing strategy. @@ -3433,14 +3437,20 @@ impl<'a> Parser<'a> { pth: ast::Path, recover: bool, close_delim: Delimiter, - ) -> PResult<'a, (ThinVec, ast::StructRest, bool)> { + ) -> PResult< + 'a, + ( + ThinVec, + ast::StructRest, + Option, /* async blocks are forbidden in Rust 2015 */ + ), + > { let mut fields = ThinVec::new(); let mut base = ast::StructRest::None; - let mut recover_async = false; + let mut recovered_async = None; let in_if_guard = self.restrictions.contains(Restrictions::IN_IF_GUARD); - let mut async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { - recover_async = true; + let async_block_err = |e: &mut DiagnosticBuilder<'_>, span: Span| { errors::AsyncBlockIn2015 { span }.add_to_diagnostic(e); errors::HelpUseLatestEdition::new().add_to_diagnostic(e); }; @@ -3465,9 +3475,34 @@ impl<'a> Parser<'a> { break; } - let recovery_field = self.find_struct_error_after_field_looking_code(); + // Peek the field's ident before parsing its expr in order to emit better diagnostics. + let peek = self + .token + .ident() + .filter(|(ident, is_raw)| { + (!ident.is_reserved() || matches!(is_raw, IdentIsRaw::Yes)) + && self.look_ahead(1, |tok| *tok == token::Colon) + }) + .map(|(ident, _)| ident); + + // We still want a field even if its expr didn't parse. + let field_ident = |this: &Self, guar: ErrorGuaranteed| { + peek.map(|ident| { + let span = ident.span; + ExprField { + ident, + span, + expr: this.mk_expr_err(span, guar), + is_shorthand: false, + attrs: AttrVec::new(), + id: DUMMY_NODE_ID, + is_placeholder: false, + } + }) + }; + let parsed_field = match self.parse_expr_field() { - Ok(f) => Some(f), + Ok(f) => Ok(f), Err(mut e) => { if pth == kw::Async { async_block_err(&mut e, pth.span); @@ -3499,7 +3534,10 @@ impl<'a> Parser<'a> { return Err(e); } - e.emit(); + let guar = e.emit(); + if pth == kw::Async { + recovered_async = Some(guar); + } // If the next token is a comma, then try to parse // what comes next as additional fields, rather than @@ -3511,18 +3549,20 @@ impl<'a> Parser<'a> { } } - None + Err(guar) } }; - let is_shorthand = parsed_field.as_ref().is_some_and(|f| f.is_shorthand); + let is_shorthand = parsed_field.as_ref().is_ok_and(|f| f.is_shorthand); // A shorthand field can be turned into a full field with `:`. // We should point this out. self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon)); match self.expect_one_of(&[token::Comma], &[token::CloseDelim(close_delim)]) { Ok(_) => { - if let Some(f) = parsed_field.or(recovery_field) { + if let Some(f) = + parsed_field.or_else(|guar| field_ident(self, guar).ok_or(guar)).ok() + { // Only include the field if there's no parse error for the field name. fields.push(f); } @@ -3532,8 +3572,7 @@ impl<'a> Parser<'a> { async_block_err(&mut e, pth.span); } else { e.span_label(pth.span, "while parsing this struct"); - if let Some(f) = recovery_field { - fields.push(f); + if peek.is_some() { e.span_suggestion( self.prev_token.span.shrink_to_hi(), "try adding a comma", @@ -3545,13 +3584,18 @@ impl<'a> Parser<'a> { if !recover { return Err(e); } - e.emit(); + let guar = e.emit(); + if pth == kw::Async { + recovered_async = Some(guar); + } else if let Some(f) = field_ident(self, guar) { + fields.push(f); + } self.recover_stmt_(SemiColonMode::Comma, BlockMode::Ignore); self.eat(&token::Comma); } } } - Ok((fields, base, recover_async)) + Ok((fields, base, recovered_async)) } /// Precondition: already parsed the '{'. @@ -3562,39 +3606,18 @@ impl<'a> Parser<'a> { recover: bool, ) -> PResult<'a, P> { let lo = pth.span; - let (fields, base, recover_async) = + let (fields, base, recovered_async) = self.parse_struct_fields(pth.clone(), recover, Delimiter::Brace)?; let span = lo.to(self.token.span); self.expect(&token::CloseDelim(Delimiter::Brace))?; - let expr = if recover_async { - ExprKind::Err + let expr = if let Some(guar) = recovered_async { + ExprKind::Err(guar) } else { ExprKind::Struct(P(ast::StructExpr { qself, path: pth, fields, rest: base })) }; Ok(self.mk_expr(span, expr)) } - /// Use in case of error after field-looking code: `S { foo: () with a }`. - fn find_struct_error_after_field_looking_code(&self) -> Option { - match self.token.ident() { - Some((ident, is_raw)) - if (matches!(is_raw, IdentIsRaw::Yes) || !ident.is_reserved()) - && self.look_ahead(1, |t| *t == token::Colon) => - { - Some(ast::ExprField { - ident, - span: self.token.span, - expr: self.mk_expr_err(self.token.span), - is_shorthand: false, - attrs: AttrVec::new(), - id: DUMMY_NODE_ID, - is_placeholder: false, - }) - } - _ => None, - } - } - fn recover_struct_comma_after_dotdot(&mut self, span: Span) { if self.token != token::Comma { return; @@ -3718,8 +3741,8 @@ impl<'a> Parser<'a> { limits: RangeLimits, ) -> ExprKind { if end.is_none() && limits == RangeLimits::Closed { - self.inclusive_range_with_incorrect_end(); - ExprKind::Err + let guar = self.inclusive_range_with_incorrect_end(); + ExprKind::Err(guar) } else { ExprKind::Range(start, end, limits) } @@ -3756,8 +3779,8 @@ impl<'a> Parser<'a> { self.mk_expr_with_attrs(span, kind, AttrVec::new()) } - pub(super) fn mk_expr_err(&self, span: Span) -> P { - self.mk_expr(span, ExprKind::Err) + pub(super) fn mk_expr_err(&self, span: Span, guar: ErrorGuaranteed) -> P { + self.mk_expr(span, ExprKind::Err(guar)) } /// Create expression span ensuring the span of the parent node @@ -3949,7 +3972,7 @@ impl MutVisitor for CondChecker<'_> { | ExprKind::Become(_) | ExprKind::IncludedBytes(_) | ExprKind::FormatArgs(_) - | ExprKind::Err + | ExprKind::Err(_) | ExprKind::Dummy => { // These would forbid any let expressions they contain already. } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 2e049ca908fd4..a678194372e9b 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -2328,11 +2328,11 @@ impl<'a> Parser<'a> { let _ = self.parse_expr()?; self.expect_semi()?; // `;` let span = eq_sp.to(self.prev_token.span); - self.dcx().emit_err(errors::FunctionBodyEqualsExpr { + let guar = self.dcx().emit_err(errors::FunctionBodyEqualsExpr { span, sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span }, }); - (AttrVec::new(), Some(self.mk_block_err(span))) + (AttrVec::new(), Some(self.mk_block_err(span, guar))) } else { let expected = if req_body { &[token::OpenDelim(Delimiter::Brace)][..] diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs index c82b44ac6e100..9bff5b9309250 100644 --- a/compiler/rustc_parse/src/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -566,7 +566,7 @@ impl<'a> Parser<'a> { match self.parse_literal_maybe_minus() { Ok(begin) => { let begin = match self.maybe_recover_trailing_expr(begin.span, false) { - Some(_) => self.mk_expr_err(begin.span), + Some(guar) => self.mk_expr_err(begin.span, guar), None => begin, }; @@ -719,7 +719,7 @@ impl<'a> Parser<'a> { self.parse_pat_range_begin_with(begin.clone(), form) } // recover ranges with parentheses around the `(start)..` - PatKind::Err(_) + PatKind::Err(guar) if self.may_recover() && let Some(form) = self.parse_range_end() => { @@ -731,7 +731,7 @@ impl<'a> Parser<'a> { }, }); - self.parse_pat_range_begin_with(self.mk_expr(pat.span, ExprKind::Err), form) + self.parse_pat_range_begin_with(self.mk_expr_err(pat.span, *guar), form) } // (pat) with optional parentheses @@ -886,7 +886,7 @@ impl<'a> Parser<'a> { Ok(PatKind::Range(Some(begin), end, re)) } - pub(super) fn inclusive_range_with_incorrect_end(&mut self) { + pub(super) fn inclusive_range_with_incorrect_end(&mut self) -> ErrorGuaranteed { let tok = &self.token; let span = self.prev_token.span; // If the user typed "..==" instead of "..=", we want to give them @@ -905,15 +905,13 @@ impl<'a> Parser<'a> { let _ = self.parse_pat_range_end().map_err(|e| e.cancel()); } - self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }); + self.dcx().emit_err(InclusiveRangeExtraEquals { span: span_with_eq }) } token::Gt if no_space => { let after_pat = span.with_hi(span.hi() - rustc_span::BytePos(1)).shrink_to_hi(); - self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }); - } - _ => { - self.dcx().emit_err(InclusiveRangeNoEnd { span }); + self.dcx().emit_err(InclusiveRangeMatchArrow { span, arrow: tok.span, after_pat }) } + _ => self.dcx().emit_err(InclusiveRangeNoEnd { span }), } } @@ -987,7 +985,7 @@ impl<'a> Parser<'a> { } Ok(match recovered { - Some(_) => self.mk_expr_err(bound.span), + Some(guar) => self.mk_expr_err(bound.span, guar), None => bound, }) } diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ee02b69c6140d..15f8124823fb0 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -22,7 +22,7 @@ use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt}; use rustc_ast::{StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::symbol::{kw, sym, Ident}; -use rustc_span::{BytePos, Span}; +use rustc_span::{BytePos, ErrorGuaranteed, Span}; use std::borrow::Cow; use std::mem; @@ -610,9 +610,9 @@ impl<'a> Parser<'a> { } } - err.emit(); + let guar = err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); - Some(self.mk_stmt_err(self.token.span)) + Some(self.mk_stmt_err(self.token.span, guar)) } Ok(stmt) => stmt, Err(err) => return Err(err), @@ -651,10 +651,10 @@ impl<'a> Parser<'a> { .contains(&self.token.kind) => { // The user has written `#[attr] expr` which is unsupported. (#106020) - self.attr_on_non_tail_expr(&expr); + let guar = self.attr_on_non_tail_expr(&expr); // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); - *expr = self.mk_expr_err(sp); + *expr = self.mk_expr_err(sp, guar); } // Expression without semicolon. @@ -666,10 +666,18 @@ impl<'a> Parser<'a> { let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]); + // Try to both emit a better diagnostic, and avoid further errors by replacing + // the `expr` with `ExprKind::Err`. let replace_with_err = 'break_recover: { match expect_result { - // Recover from parser, skip type error to avoid extra errors. - Ok(Recovered::Yes) => true, + Ok(Recovered::No) => None, + Ok(Recovered::Yes) => { + // Skip type error to avoid extra errors. + let guar = self + .dcx() + .span_delayed_bug(self.prev_token.span, "expected `;` or `}`"); + Some(guar) + } Err(e) => { if self.recover_colon_as_semi() { // recover_colon_as_semi has already emitted a nicer error. @@ -677,7 +685,7 @@ impl<'a> Parser<'a> { add_semi_to_stmt = true; eat_semi = false; - break 'break_recover false; + break 'break_recover None; } match &expr.kind { @@ -705,13 +713,13 @@ impl<'a> Parser<'a> { }; match self.parse_expr_labeled(label, false) { Ok(labeled_expr) => { - e.delay_as_bug(); + e.cancel(); self.dcx().emit_err(MalformedLoopLabel { span: label.ident.span, correct_label: label.ident, }); *expr = labeled_expr; - break 'break_recover false; + break 'break_recover None; } Err(err) => { err.cancel(); @@ -723,26 +731,26 @@ impl<'a> Parser<'a> { _ => {} } - if let Err(e) = - self.check_mistyped_turbofish_with_multiple_type_params(e, expr) - { - if recover.no() { - return Err(e); - } - e.emit(); - self.recover_stmt(); - } - - true + let res = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr); + + Some(if recover.no() { + res? + } else { + res.unwrap_or_else(|e| { + let guar = e.emit(); + self.recover_stmt(); + guar + }) + }) } - Ok(Recovered::No) => false, } }; - if replace_with_err { + if let Some(guar) = replace_with_err { // We already emitted an error, so don't emit another type error let sp = expr.span.to(self.prev_token.span); - *expr = self.mk_expr_err(sp); + *expr = self.mk_expr_err(sp, guar); } } StmtKind::Expr(_) | StmtKind::MacCall(_) => {} @@ -791,11 +799,11 @@ impl<'a> Parser<'a> { Stmt { id: DUMMY_NODE_ID, kind, span } } - pub(super) fn mk_stmt_err(&self, span: Span) -> Stmt { - self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span))) + pub(super) fn mk_stmt_err(&self, span: Span, guar: ErrorGuaranteed) -> Stmt { + self.mk_stmt(span, StmtKind::Expr(self.mk_expr_err(span, guar))) } - pub(super) fn mk_block_err(&self, span: Span) -> P { - self.mk_block(thin_vec![self.mk_stmt_err(span)], BlockCheckMode::Default, span) + pub(super) fn mk_block_err(&self, span: Span, guar: ErrorGuaranteed) -> P { + self.mk_block(thin_vec![self.mk_stmt_err(span, guar)], BlockCheckMode::Default, span) } } diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs index 5d46581f646cc..73c92708eb39c 100644 --- a/compiler/rustc_parse/src/validate_attr.rs +++ b/compiler/rustc_parse/src/validate_attr.rs @@ -90,7 +90,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta // been reported. let msg = "attribute value must be a literal"; let mut err = sess.dcx.struct_span_err(expr.span, msg); - if let ast::ExprKind::Err = expr.kind { + if let ast::ExprKind::Err(_) = expr.kind { err.downgrade_to_delayed_bug(); } return Err(err); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 81a26a12009d1..c52a4e0d8b7c7 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { match (&l.kind, &r.kind) { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), - (Err, Err) => true, + (Err(_), Err(_)) => true, (Dummy, _) | (_, Dummy) => unreachable!("comparing `ExprKind::Dummy`"), (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index 7b1b0388b29f3..1f6446b8746e6 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -222,7 +222,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::Array(..) | ast::ExprKind::While(..) | ast::ExprKind::Await(..) - | ast::ExprKind::Err + | ast::ExprKind::Err(_) | ast::ExprKind::Dummy => Sugg::NonParen(snippet_with_context(cx, expr.span, ctxt, default, app).0), ast::ExprKind::Range(ref lhs, ref rhs, RangeLimits::HalfOpen) => Sugg::BinOp( AssocOp::DotDot, diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index d46d7c53bdb47..c500b30b99826 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -404,7 +404,7 @@ pub(crate) fn format_expr( // These do not occur in the AST because macros aren't expanded. unreachable!() } - ast::ExprKind::Err | ast::ExprKind::Dummy => None, + ast::ExprKind::Err(_) | ast::ExprKind::Dummy => None, }; expr_rw diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index b6b37e492e92f..d4218cff75aaa 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -498,7 +498,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Cast(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Dummy - | ast::ExprKind::Err + | ast::ExprKind::Err(_) | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) From 34eae07ee52ea0c79b07babc39ae9f139a930091 Mon Sep 17 00:00:00 2001 From: Lieselotte <52315535+she3py@users.noreply.github.com> Date: Sun, 25 Feb 2024 22:25:26 +0100 Subject: [PATCH 3/3] Remove `ast::` & `base::` prefixes from some builtin macros --- compiler/rustc_builtin_macros/src/cfg.rs | 4 +- .../rustc_builtin_macros/src/compile_error.rs | 4 +- compiler/rustc_builtin_macros/src/concat.rs | 44 +++++---- .../rustc_builtin_macros/src/concat_bytes.rs | 89 +++++++++---------- .../rustc_builtin_macros/src/concat_idents.rs | 26 +++--- compiler/rustc_builtin_macros/src/env.rs | 20 +++-- .../rustc_builtin_macros/src/source_util.rs | 47 +++++----- 7 files changed, 116 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs index ca66bc0da0cc7..04bf7dceeff49 100644 --- a/compiler/rustc_builtin_macros/src/cfg.rs +++ b/compiler/rustc_builtin_macros/src/cfg.rs @@ -8,14 +8,14 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_attr as attr; use rustc_errors::PResult; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_span::Span; pub fn expand_cfg( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); match parse_cfg(cx, sp, tts) { diff --git a/compiler/rustc_builtin_macros/src/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs index 6650035127296..b4455d7823f35 100644 --- a/compiler/rustc_builtin_macros/src/compile_error.rs +++ b/compiler/rustc_builtin_macros/src/compile_error.rs @@ -1,14 +1,14 @@ // The compiler code necessary to support the compile_error! extension. use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{get_single_str_from_tts, DummyResult, ExtCtxt, MacResult}; use rustc_span::Span; pub fn expand_compile_error<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "compile_error!") { Ok(var) => var, Err(guar) => return DummyResult::any(sp, guar), diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs index dd4a0e7f22869..abfaa9b006edb 100644 --- a/compiler/rustc_builtin_macros/src/concat.rs +++ b/compiler/rustc_builtin_macros/src/concat.rs @@ -1,17 +1,17 @@ -use rustc_ast as ast; use rustc_ast::tokenstream::TokenStream; -use rustc_expand::base::{self, DummyResult}; +use rustc_ast::{ExprKind, LitKind, UnOp}; +use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_session::errors::report_lit_error; use rustc_span::symbol::Symbol; use crate::errors; pub fn expand_concat( - cx: &mut base::ExtCtxt<'_>, + cx: &mut ExtCtxt<'_>, sp: rustc_span::Span, tts: TokenStream, -) -> Box { - let es = match base::get_exprs_from_tts(cx, tts) { +) -> Box { + let es = match get_exprs_from_tts(cx, tts) { Ok(es) => es, Err(guar) => return DummyResult::any(sp, guar), }; @@ -20,26 +20,26 @@ pub fn expand_concat( let mut guar = None; for e in es { match e.kind { - ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Str(s, _) | ast::LitKind::Float(s, _)) => { + ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Str(s, _) | LitKind::Float(s, _)) => { accumulator.push_str(s.as_str()); } - Ok(ast::LitKind::Char(c)) => { + Ok(LitKind::Char(c)) => { accumulator.push(c); } - Ok(ast::LitKind::Int(i, _)) => { + Ok(LitKind::Int(i, _)) => { accumulator.push_str(&i.to_string()); } - Ok(ast::LitKind::Bool(b)) => { + Ok(LitKind::Bool(b)) => { accumulator.push_str(&b.to_string()); } - Ok(ast::LitKind::CStr(..)) => { + Ok(LitKind::CStr(..)) => { guar = Some(cx.dcx().emit_err(errors::ConcatCStrLit { span: e.span })); } - Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => { + Ok(LitKind::Byte(..) | LitKind::ByteStr(..)) => { guar = Some(cx.dcx().emit_err(errors::ConcatBytestr { span: e.span })); } - Ok(ast::LitKind::Err(guarantee)) => { + Ok(LitKind::Err(guarantee)) => { guar = Some(guarantee); } Err(err) => { @@ -47,25 +47,23 @@ pub fn expand_concat( } }, // We also want to allow negative numeric literals. - ast::ExprKind::Unary(ast::UnOp::Neg, ref expr) - if let ast::ExprKind::Lit(token_lit) = expr.kind => - { - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), - Ok(ast::LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), + ExprKind::Unary(UnOp::Neg, ref expr) if let ExprKind::Lit(token_lit) = expr.kind => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int(i, _)) => accumulator.push_str(&format!("-{i}")), + Ok(LitKind::Float(f, _)) => accumulator.push_str(&format!("-{f}")), Err(err) => { guar = Some(report_lit_error(&cx.sess.parse_sess, err, token_lit, e.span)); } _ => missing_literal.push(e.span), } } - ast::ExprKind::IncludedBytes(..) => { + ExprKind::IncludedBytes(..) => { cx.dcx().emit_err(errors::ConcatBytestr { span: e.span }); } - ast::ExprKind::Err(guarantee) => { + ExprKind::Err(guarantee) => { guar = Some(guarantee); } - ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literal.push(e.span); } @@ -79,5 +77,5 @@ pub fn expand_concat( return DummyResult::any(sp, guar); } let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&accumulator))) } diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs index 32e17112d8c45..3fb0b50f41756 100644 --- a/compiler/rustc_builtin_macros/src/concat_bytes.rs +++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs @@ -1,6 +1,5 @@ -use rustc_ast as ast; -use rustc_ast::{ptr::P, tokenstream::TokenStream}; -use rustc_expand::base::{self, DummyResult}; +use rustc_ast::{ptr::P, token, tokenstream::TokenStream, ExprKind, LitIntType, LitKind, UintTy}; +use rustc_expand::base::{get_exprs_from_tts, DummyResult, ExtCtxt, MacEager, MacResult}; use rustc_session::errors::report_lit_error; use rustc_span::{ErrorGuaranteed, Span}; @@ -8,8 +7,8 @@ use crate::errors; /// Emits errors for literal expressions that are invalid inside and outside of an array. fn invalid_type_err( - cx: &mut base::ExtCtxt<'_>, - token_lit: ast::token::Lit, + cx: &mut ExtCtxt<'_>, + token_lit: token::Lit, span: Span, is_nested: bool, ) -> ErrorGuaranteed { @@ -18,18 +17,18 @@ fn invalid_type_err( }; let snippet = cx.sess.source_map().span_to_snippet(span).ok(); let dcx = cx.dcx(); - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::CStr(_, _)) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::CStr(_, _)) => { // Avoid ambiguity in handling of terminal `NUL` by refusing to // concatenate C string literals as bytes. dcx.emit_err(errors::ConcatCStrLit { span }) } - Ok(ast::LitKind::Char(_)) => { + Ok(LitKind::Char(_)) => { let sugg = snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "character", sugg }) } - Ok(ast::LitKind::Str(_, _)) => { + Ok(LitKind::Str(_, _)) => { // suggestion would be invalid if we are nested let sugg = if !is_nested { snippet.map(|snippet| ConcatBytesInvalidSuggestion::StrLit { span, snippet }) @@ -38,27 +37,24 @@ fn invalid_type_err( }; dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "string", sugg }) } - Ok(ast::LitKind::Float(_, _)) => { + Ok(LitKind::Float(_, _)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "float", sugg: None }) } - Ok(ast::LitKind::Bool(_)) => { + Ok(LitKind::Bool(_)) => { dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "boolean", sugg: None }) } - Ok(ast::LitKind::Int(_, _)) if !is_nested => { + Ok(LitKind::Int(_, _)) if !is_nested => { let sugg = - snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span: span, snippet }); + snippet.map(|snippet| ConcatBytesInvalidSuggestion::IntLit { span, snippet }); dcx.emit_err(ConcatBytesInvalid { span, lit_kind: "numeric", sugg }) } - Ok(ast::LitKind::Int( - val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), - )) => { + Ok(LitKind::Int(val, LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8))) => { assert!(val.get() > u8::MAX.into()); // must be an error dcx.emit_err(ConcatBytesOob { span }) } - Ok(ast::LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), - Ok(ast::LitKind::ByteStr(..) | ast::LitKind::Byte(_)) => unreachable!(), - Ok(ast::LitKind::Err(guar)) => guar, + Ok(LitKind::Int(_, _)) => dcx.emit_err(ConcatBytesNonU8 { span }), + Ok(LitKind::ByteStr(..) | LitKind::Byte(_)) => unreachable!(), + Ok(LitKind::Err(guar)) => guar, Err(err) => report_lit_error(&cx.sess.parse_sess, err, token_lit, span), } } @@ -68,7 +64,7 @@ fn invalid_type_err( /// Otherwise, returns `None`, and either pushes the `expr`'s span to `missing_literals` or /// updates `guar` accordingly. fn handle_array_element( - cx: &mut base::ExtCtxt<'_>, + cx: &mut ExtCtxt<'_>, guar: &mut Option, missing_literals: &mut Vec, expr: &P, @@ -76,16 +72,16 @@ fn handle_array_element( let dcx = cx.dcx(); match expr.kind { - ast::ExprKind::Lit(token_lit) => { - match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Int( + ExprKind::Lit(token_lit) => { + match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Int( val, - ast::LitIntType::Unsuffixed | ast::LitIntType::Unsigned(ast::UintTy::U8), + LitIntType::Unsuffixed | LitIntType::Unsigned(UintTy::U8), )) if let Ok(val) = u8::try_from(val.get()) => { return Some(val); } - Ok(ast::LitKind::Byte(val)) => return Some(val), - Ok(ast::LitKind::ByteStr(..)) => { + Ok(LitKind::Byte(val)) => return Some(val), + Ok(LitKind::ByteStr(..)) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: true }) }); @@ -95,12 +91,12 @@ fn handle_array_element( } }; } - ast::ExprKind::Array(_) | ast::ExprKind::Repeat(_, _) => { + ExprKind::Array(_) | ExprKind::Repeat(_, _) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) }); } - ast::ExprKind::IncludedBytes(..) => { + ExprKind::IncludedBytes(..) => { guar.get_or_insert_with(|| { dcx.emit_err(errors::ConcatBytesArray { span: expr.span, bytestr: false }) }); @@ -112,11 +108,11 @@ fn handle_array_element( } pub fn expand_concat_bytes( - cx: &mut base::ExtCtxt<'_>, - sp: rustc_span::Span, + cx: &mut ExtCtxt<'_>, + sp: Span, tts: TokenStream, -) -> Box { - let es = match base::get_exprs_from_tts(cx, tts) { +) -> Box { + let es = match get_exprs_from_tts(cx, tts) { Ok(es) => es, Err(guar) => return DummyResult::any(sp, guar), }; @@ -125,7 +121,7 @@ pub fn expand_concat_bytes( let mut guar = None; for e in es { match &e.kind { - ast::ExprKind::Array(exprs) => { + ExprKind::Array(exprs) => { for expr in exprs { if let Some(elem) = handle_array_element(cx, &mut guar, &mut missing_literals, expr) @@ -134,10 +130,9 @@ pub fn expand_concat_bytes( } } } - ast::ExprKind::Repeat(expr, count) => { - if let ast::ExprKind::Lit(token_lit) = count.value.kind - && let Ok(ast::LitKind::Int(count_val, _)) = - ast::LitKind::from_token_lit(token_lit) + ExprKind::Repeat(expr, count) => { + if let ExprKind::Lit(token_lit) = count.value.kind + && let Ok(LitKind::Int(count_val, _)) = LitKind::from_token_lit(token_lit) { if let Some(elem) = handle_array_element(cx, &mut guar, &mut missing_literals, expr) @@ -152,24 +147,24 @@ pub fn expand_concat_bytes( ); } } - &ast::ExprKind::Lit(token_lit) => match ast::LitKind::from_token_lit(token_lit) { - Ok(ast::LitKind::Byte(val)) => { + &ExprKind::Lit(token_lit) => match LitKind::from_token_lit(token_lit) { + Ok(LitKind::Byte(val)) => { accumulator.push(val); } - Ok(ast::LitKind::ByteStr(ref bytes, _)) => { + Ok(LitKind::ByteStr(ref bytes, _)) => { accumulator.extend_from_slice(bytes); } _ => { guar.get_or_insert_with(|| invalid_type_err(cx, token_lit, e.span, false)); } }, - ast::ExprKind::IncludedBytes(bytes) => { + ExprKind::IncludedBytes(bytes) => { accumulator.extend_from_slice(bytes); } - ast::ExprKind::Err(guarantee) => { + ExprKind::Err(guarantee) => { guar = Some(*guarantee); } - ast::ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), + ExprKind::Dummy => cx.dcx().span_bug(e.span, "concatenating `ExprKind::Dummy`"), _ => { missing_literals.push(e.span); } @@ -177,10 +172,10 @@ pub fn expand_concat_bytes( } if !missing_literals.is_empty() { let guar = cx.dcx().emit_err(errors::ConcatBytesMissingLiteral { spans: missing_literals }); - return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + return MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } else if let Some(guar) = guar { - return base::MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); + return MacEager::expr(DummyResult::raw_expr(sp, Some(guar))); } let sp = cx.with_def_site_ctxt(sp); - base::MacEager::expr(cx.expr_byte_str(sp, accumulator)) + MacEager::expr(cx.expr_byte_str(sp, accumulator)) } diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs index 29d3f6164aa16..fffcddc5325bd 100644 --- a/compiler/rustc_builtin_macros/src/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -1,8 +1,8 @@ -use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, Token}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AttrVec, Expr, ExprKind, Path, Ty, TyKind, DUMMY_NODE_ID}; +use rustc_expand::base::{DummyResult, ExtCtxt, MacResult}; use rustc_span::symbol::{Ident, Symbol}; use rustc_span::Span; @@ -12,7 +12,7 @@ pub fn expand_concat_idents<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { if tts.is_empty() { let guar = cx.dcx().emit_err(errors::ConcatIdentsMissingArgs { span: sp }); return DummyResult::any(sp, guar); @@ -47,21 +47,21 @@ pub fn expand_concat_idents<'cx>( ident: Ident, } - impl base::MacResult for ConcatIdentsResult { - fn make_expr(self: Box) -> Option> { - Some(P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::Path(None, ast::Path::from_ident(self.ident)), + impl MacResult for ConcatIdentsResult { + fn make_expr(self: Box) -> Option> { + Some(P(Expr { + id: DUMMY_NODE_ID, + kind: ExprKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, - attrs: ast::AttrVec::new(), + attrs: AttrVec::new(), tokens: None, })) } - fn make_ty(self: Box) -> Option> { - Some(P(ast::Ty { - id: ast::DUMMY_NODE_ID, - kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), + fn make_ty(self: Box) -> Option> { + Some(P(Ty { + id: DUMMY_NODE_ID, + kind: TyKind::Path(None, Path::from_ident(self.ident)), span: self.ident.span, tokens: None, })) diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs index 67ace546ad042..f057d44bf710a 100644 --- a/compiler/rustc_builtin_macros/src/env.rs +++ b/compiler/rustc_builtin_macros/src/env.rs @@ -3,9 +3,13 @@ // interface. // +use rustc_ast::token::{self, LitKind}; use rustc_ast::tokenstream::TokenStream; -use rustc_ast::{self as ast, AstDeref, GenericArg}; -use rustc_expand::base::{self, *}; +use rustc_ast::{AstDeref, ExprKind, GenericArg, Mutability}; +use rustc_expand::base::{ + expr_to_string, get_exprs_from_tts, get_single_str_from_tts, DummyResult, ExtCtxt, MacEager, + MacResult, +}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; use std::env; @@ -27,7 +31,7 @@ pub fn expand_option_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let var = match get_single_str_from_tts(cx, sp, tts, "option_env!") { Ok(var) => var, Err(guar) => return DummyResult::any(sp, guar), @@ -47,7 +51,7 @@ pub fn expand_option_env<'cx>( sp, cx.ty_ident(sp, Ident::new(sym::str, sp)), Some(lt), - ast::Mutability::Not, + Mutability::Not, ))], )) } @@ -64,7 +68,7 @@ pub fn expand_env<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let mut exprs = match get_exprs_from_tts(cx, tts) { Ok(exprs) if exprs.is_empty() || exprs.len() > 2 => { let guar = cx.dcx().emit_err(errors::EnvTakesArgs { span: sp }); @@ -93,10 +97,8 @@ pub fn expand_env<'cx>( cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value)); let e = match value { None => { - let ast::ExprKind::Lit(ast::token::Lit { - kind: ast::token::LitKind::Str | ast::token::LitKind::StrRaw(..), - symbol, - .. + let ExprKind::Lit(token::Lit { + kind: LitKind::Str | LitKind::StrRaw(..), symbol, .. }) = &var_expr.kind else { unreachable!("`expr_to_string` ensures this is a string lit") diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs index 3860057e1d412..8e0978de23748 100644 --- a/compiler/rustc_builtin_macros/src/source_util.rs +++ b/compiler/rustc_builtin_macros/src/source_util.rs @@ -3,7 +3,10 @@ use rustc_ast::ptr::P; use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast_pretty::pprust; -use rustc_expand::base::{self, *}; +use rustc_expand::base::{ + check_zero_tts, get_single_str_from_tts, parse_expr, resolve_path, DummyResult, ExtCtxt, + MacEager, MacResult, +}; use rustc_expand::module::DirOwnership; use rustc_parse::new_parser_from_file; use rustc_parse::parser::{ForceCollect, Parser}; @@ -23,14 +26,14 @@ pub fn expand_line( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "line!"); + check_zero_tts(cx, sp, tts, "line!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) + MacEager::expr(cx.expr_u32(topmost, loc.line as u32)) } /* column!(): expands to the current column number */ @@ -38,14 +41,14 @@ pub fn expand_column( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "column!"); + check_zero_tts(cx, sp, tts, "column!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); - base::MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)) + MacEager::expr(cx.expr_u32(topmost, loc.col.to_usize() as u32 + 1)) } /// file!(): expands to the current filename */ @@ -55,15 +58,15 @@ pub fn expand_file( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "file!"); + check_zero_tts(cx, sp, tts, "file!"); let topmost = cx.expansion_cause().unwrap_or(sp); let loc = cx.source_map().lookup_char_pos(topmost.lo()); use rustc_session::{config::RemapPathScopeComponents, RemapFileNameExt}; - base::MacEager::expr(cx.expr_str( + MacEager::expr(cx.expr_str( topmost, Symbol::intern( &loc.file.name.for_scope(cx.sess, RemapPathScopeComponents::MACRO).to_string_lossy(), @@ -75,23 +78,23 @@ pub fn expand_stringify( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let s = pprust::tts_to_string(&tts); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&s))) } pub fn expand_mod( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); - base::check_zero_tts(cx, sp, tts, "module_path!"); + check_zero_tts(cx, sp, tts, "module_path!"); let mod_path = &cx.current_expansion.module.mod_path; let string = mod_path.iter().map(|x| x.to_string()).collect::>().join("::"); - base::MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))) + MacEager::expr(cx.expr_str(sp, Symbol::intern(&string))) } /// include! : parse the given file as an expr @@ -101,7 +104,7 @@ pub fn expand_include<'cx>( cx: &'cx mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include!") { Ok(file) => file, @@ -129,9 +132,9 @@ pub fn expand_include<'cx>( p: Parser<'a>, node_id: ast::NodeId, } - impl<'a> base::MacResult for ExpandResult<'a> { + impl<'a> MacResult for ExpandResult<'a> { fn make_expr(mut self: Box>) -> Option> { - let expr = base::parse_expr(&mut self.p).ok()?; + let expr = parse_expr(&mut self.p).ok()?; if self.p.token != token::Eof { self.p.sess.buffer_lint( INCOMPLETE_INCLUDE, @@ -175,7 +178,7 @@ pub fn expand_include_str( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include_str!") { Ok(file) => file, @@ -192,7 +195,7 @@ pub fn expand_include_str( Ok(bytes) => match std::str::from_utf8(&bytes) { Ok(src) => { let interned_src = Symbol::intern(src); - base::MacEager::expr(cx.expr_str(sp, interned_src)) + MacEager::expr(cx.expr_str(sp, interned_src)) } Err(_) => { let guar = cx.dcx().span_err(sp, format!("{} wasn't a utf-8 file", file.display())); @@ -210,7 +213,7 @@ pub fn expand_include_bytes( cx: &mut ExtCtxt<'_>, sp: Span, tts: TokenStream, -) -> Box { +) -> Box { let sp = cx.with_def_site_ctxt(sp); let file = match get_single_str_from_tts(cx, sp, tts, "include_bytes!") { Ok(file) => file, @@ -226,7 +229,7 @@ pub fn expand_include_bytes( match cx.source_map().load_binary_file(&file) { Ok(bytes) => { let expr = cx.expr(sp, ast::ExprKind::IncludedBytes(bytes)); - base::MacEager::expr(expr) + MacEager::expr(expr) } Err(e) => { let guar = cx.dcx().span_err(sp, format!("couldn't read {}: {}", file.display(), e));