diff options
| author | bors <bors@rust-lang.org> | 2018-12-27 22:27:27 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2018-12-27 22:27:27 +0000 |
| commit | f8caa321c7c7214a6c5415e4b3694e65b4ff73a7 (patch) | |
| tree | 0ba10b2287624eb95f56f7e5ddce2f7041125acd /src/libsyntax | |
| parent | fb86d604bf65c3becd16180b56267a329cf268d5 (diff) | |
| parent | bc16edeb28e38e5bbed8828fb6314b1cc5151235 (diff) | |
| download | rust-f8caa321c7c7214a6c5415e4b3694e65b4ff73a7.tar.gz rust-f8caa321c7c7214a6c5415e4b3694e65b4ff73a7.zip | |
Auto merge of #56999 - petrochenkov:macrecov2, r=estebank
AST/HIR: Introduce `ExprKind::Err` for better error recovery in the front-end This way we can avoid aborting compilation if expansion produces errors and generate `ExprKind::Err`s instead.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ast.rs | 5 | ||||
| -rw-r--r-- | src/libsyntax/ext/base.rs | 35 | ||||
| -rw-r--r-- | src/libsyntax/ext/build.rs | 1 | ||||
| -rw-r--r-- | src/libsyntax/ext/expand.rs | 17 | ||||
| -rw-r--r-- | src/libsyntax/feature_gate.rs | 19 | ||||
| -rw-r--r-- | src/libsyntax/fold.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 13 | ||||
| -rw-r--r-- | src/libsyntax/print/pprust.rs | 9 | ||||
| -rw-r--r-- | src/libsyntax/util/parser.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/visit.rs | 1 |
10 files changed, 61 insertions, 47 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index 7e228d8d7cf..e3a8980a975 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -444,7 +444,6 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }` pub rules: BlockCheckMode, pub span: Span, - pub recovered: bool, } #[derive(Clone, RustcEncodable, RustcDecodable)] @@ -1001,6 +1000,7 @@ impl Expr { ExprKind::Paren(..) => ExprPrecedence::Paren, ExprKind::Try(..) => ExprPrecedence::Try, ExprKind::Yield(..) => ExprPrecedence::Yield, + ExprKind::Err => ExprPrecedence::Err, } } } @@ -1160,6 +1160,9 @@ pub enum ExprKind { /// A `yield`, with an optional value to be yielded. Yield(Option<P<Expr>>), + + /// Placeholder for an expression that wasn't syntactically well formed in some way. + Err, } /// The explicit `Self` type in a "qualified path". The actual diff --git a/src/libsyntax/ext/base.rs b/src/libsyntax/ext/base.rs index d576397c942..1efe0b3478d 100644 --- a/src/libsyntax/ext/base.rs +++ b/src/libsyntax/ext/base.rs @@ -2,7 +2,7 @@ pub use self::SyntaxExtension::*; use ast::{self, Attribute, Name, PatKind, MetaItem}; use attr::HasAttrs; -use source_map::{self, SourceMap, Spanned, respan}; +use source_map::{SourceMap, Spanned, respan}; use syntax_pos::{Span, MultiSpan, DUMMY_SP}; use edition::Edition; use errors::{DiagnosticBuilder, DiagnosticId}; @@ -456,7 +456,8 @@ impl MacResult for MacEager { #[derive(Copy, Clone)] pub struct DummyResult { expr_only: bool, - span: Span + is_error: bool, + span: Span, } impl DummyResult { @@ -464,8 +465,13 @@ impl DummyResult { /// /// Use this as a return value after hitting any errors and /// calling `span_err`. - pub fn any(sp: Span) -> Box<dyn MacResult+'static> { - Box::new(DummyResult { expr_only: false, span: sp }) + pub fn any(span: Span) -> Box<dyn MacResult+'static> { + Box::new(DummyResult { expr_only: false, is_error: true, span }) + } + + /// Same as `any`, but must be a valid fragment, not error. + pub fn any_valid(span: Span) -> Box<dyn MacResult+'static> { + Box::new(DummyResult { expr_only: false, is_error: false, span }) } /// Create a default MacResult that can only be an expression. @@ -473,15 +479,15 @@ impl DummyResult { /// Use this for macros that must expand to an expression, so even /// if an error is encountered internally, the user will receive /// an error that they also used it in the wrong place. - pub fn expr(sp: Span) -> Box<dyn MacResult+'static> { - Box::new(DummyResult { expr_only: true, span: sp }) + pub fn expr(span: Span) -> Box<dyn MacResult+'static> { + Box::new(DummyResult { expr_only: true, is_error: true, span }) } /// A plain dummy expression. - pub fn raw_expr(sp: Span) -> P<ast::Expr> { + pub fn raw_expr(sp: Span, is_error: bool) -> P<ast::Expr> { P(ast::Expr { id: ast::DUMMY_NODE_ID, - node: ast::ExprKind::Lit(source_map::respan(sp, ast::LitKind::Bool(false))), + node: if is_error { ast::ExprKind::Err } else { ast::ExprKind::Tup(Vec::new()) }, span: sp, attrs: ThinVec::new(), }) @@ -496,10 +502,11 @@ impl DummyResult { } } - pub fn raw_ty(sp: Span) -> P<ast::Ty> { + /// A plain dummy type. + pub fn raw_ty(sp: Span, is_error: bool) -> P<ast::Ty> { P(ast::Ty { id: ast::DUMMY_NODE_ID, - node: ast::TyKind::Infer, + node: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, span: sp }) } @@ -507,7 +514,7 @@ impl DummyResult { impl MacResult for DummyResult { fn make_expr(self: Box<DummyResult>) -> Option<P<ast::Expr>> { - Some(DummyResult::raw_expr(self.span)) + Some(DummyResult::raw_expr(self.span, self.is_error)) } fn make_pat(self: Box<DummyResult>) -> Option<P<ast::Pat>> { @@ -550,13 +557,13 @@ impl MacResult for DummyResult { fn make_stmts(self: Box<DummyResult>) -> Option<SmallVec<[ast::Stmt; 1]>> { Some(smallvec![ast::Stmt { id: ast::DUMMY_NODE_ID, - node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span)), + node: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, }]) } fn make_ty(self: Box<DummyResult>) -> Option<P<ast::Ty>> { - Some(DummyResult::raw_ty(self.span)) + Some(DummyResult::raw_ty(self.span, self.is_error)) } } @@ -796,7 +803,6 @@ pub struct ExtCtxt<'a> { pub ecfg: expand::ExpansionConfig<'a>, pub root_path: PathBuf, pub resolver: &'a mut dyn Resolver, - pub resolve_err_count: usize, pub current_expansion: ExpansionData, pub expansions: FxHashMap<Span, Vec<String>>, } @@ -811,7 +817,6 @@ impl<'a> ExtCtxt<'a> { ecfg, root_path: PathBuf::new(), resolver, - resolve_err_count: 0, current_expansion: ExpansionData { mark: Mark::root(), depth: 0, diff --git a/src/libsyntax/ext/build.rs b/src/libsyntax/ext/build.rs index 15faae53916..a8eec1a74dd 100644 --- a/src/libsyntax/ext/build.rs +++ b/src/libsyntax/ext/build.rs @@ -587,7 +587,6 @@ impl<'a> AstBuilder for ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, span, - recovered: false, }) } diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs index 55012bb7f5a..3863778fe72 100644 --- a/src/libsyntax/ext/expand.rs +++ b/src/libsyntax/ext/expand.rs @@ -344,8 +344,10 @@ impl<'a, 'b> MacroExpander<'a, 'b> { // FIXME(jseyfried): Refactor out the following logic let (expanded_fragment, new_invocations) = if let Some(ext) = ext { if let Some(ext) = ext { - let dummy = invoc.fragment_kind.dummy(invoc.span()).unwrap(); - let fragment = self.expand_invoc(invoc, &*ext).unwrap_or(dummy); + let (invoc_fragment_kind, invoc_span) = (invoc.fragment_kind, invoc.span()); + let fragment = self.expand_invoc(invoc, &*ext).unwrap_or_else(|| { + invoc_fragment_kind.dummy(invoc_span).unwrap() + }); self.collect_invocations(fragment, &[]) } else if let InvocationKind::Attr { attr: None, traits, item, .. } = invoc.kind { if !item.derive_allowed() { @@ -431,9 +433,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn resolve_imports(&mut self) { if self.monotonic { - let err_count = self.cx.parse_sess.span_diagnostic.err_count(); self.cx.resolver.resolve_imports(); - self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; } } @@ -457,11 +457,9 @@ impl<'a, 'b> MacroExpander<'a, 'b> { }; if self.monotonic { - let err_count = self.cx.parse_sess.span_diagnostic.err_count(); - let mark = self.cx.current_expansion.mark; - self.cx.resolver.visit_ast_fragment_with_placeholders(mark, &fragment_with_placeholders, - derives); - self.cx.resolve_err_count += self.cx.parse_sess.span_diagnostic.err_count() - err_count; + self.cx.resolver.visit_ast_fragment_with_placeholders( + self.cx.current_expansion.mark, &fragment_with_placeholders, derives + ); } (fragment_with_placeholders, invocations) @@ -724,7 +722,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> { emit_feature_err(this.cx.parse_sess, &*feature.as_str(), span, GateIssue::Library(Some(issue)), &explain); this.cx.trace_macros_diag(); - return Err(kind.dummy(span)); } } diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 62269a8f163..70df403d0c2 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -1272,16 +1272,15 @@ impl<'a> Context<'a> { return; } } - if name.starts_with("rustc_") { - gate_feature!(self, rustc_attrs, attr.span, - "unless otherwise specified, attributes \ - with the prefix `rustc_` \ - are reserved for internal compiler diagnostics"); - } else if !attr::is_known(attr) { - // Only run the custom attribute lint during regular feature gate - // checking. Macro gating runs before the plugin attributes are - // registered, so we skip this in that case. - if !is_macro { + if !attr::is_known(attr) { + if name.starts_with("rustc_") { + let msg = "unless otherwise specified, attributes with the prefix `rustc_` \ + are reserved for internal compiler diagnostics"; + gate_feature!(self, rustc_attrs, attr.span, msg); + } else if !is_macro { + // Only run the custom attribute lint during regular feature gate + // checking. Macro gating runs before the plugin attributes are + // registered, so we skip this in that case. let msg = format!("The attribute `{}` is currently unknown to the compiler and \ may have meaning added to it in the future", attr.path); gate_feature!(self, custom_attribute, attr.span, &msg); diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 0abc74c2314..8ac103856dc 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -892,12 +892,11 @@ fn noop_fold_bounds<T: Folder>(bounds: GenericBounds, folder: &mut T) } pub fn noop_fold_block<T: Folder>(b: P<Block>, folder: &mut T) -> P<Block> { - b.map(|Block {id, stmts, rules, span, recovered}| Block { + b.map(|Block {id, stmts, rules, span}| Block { id: folder.new_id(id), stmts: stmts.move_flat_map(|s| folder.fold_stmt(s).into_iter()), rules, span: folder.new_span(span), - recovered, }) } @@ -1367,6 +1366,7 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span, attrs}: Expr, folder: &mu ExprKind::Yield(ex) => ExprKind::Yield(ex.map(|x| folder.fold_expr(x))), ExprKind::Try(ex) => ExprKind::Try(folder.fold_expr(ex)), ExprKind::TryBlock(body) => ExprKind::TryBlock(folder.fold_block(body)), + ExprKind::Err => ExprKind::Err, }, id: folder.new_id(id), span: folder.new_span(span), diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index e6f0d871222..52da8a072c7 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -32,6 +32,7 @@ use ast::{UseTree, UseTreeKind}; use ast::{BinOpKind, UnOp}; use ast::{RangeEnd, RangeSyntax}; use {ast, attr}; +use ext::base::DummyResult; use source_map::{self, SourceMap, Spanned, respan}; use syntax_pos::{self, Span, MultiSpan, BytePos, FileName}; use errors::{self, Applicability, DiagnosticBuilder, DiagnosticId}; @@ -2870,6 +2871,7 @@ impl<'a> Parser<'a> { let mut err = self.fatal(&format!("unknown macro variable `{}`", name)); err.span_label(self.span, "unknown macro variable"); err.emit(); + self.bump(); return } token::Interpolated(ref nt) => { @@ -4966,16 +4968,16 @@ impl<'a> Parser<'a> { /// Precondition: already parsed the '{'. fn parse_block_tail(&mut self, lo: Span, s: BlockCheckMode) -> PResult<'a, P<Block>> { let mut stmts = vec![]; - let mut recovered = false; - while !self.eat(&token::CloseDelim(token::Brace)) { let stmt = match self.parse_full_stmt(false) { Err(mut err) => { err.emit(); self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore); - self.eat(&token::CloseDelim(token::Brace)); - recovered = true; - break; + Some(Stmt { + id: ast::DUMMY_NODE_ID, + node: StmtKind::Expr(DummyResult::raw_expr(self.span, true)), + span: self.span, + }) } Ok(stmt) => stmt, }; @@ -4993,7 +4995,6 @@ impl<'a> Parser<'a> { id: ast::DUMMY_NODE_ID, rules: s, span: lo.to(self.prev_span), - recovered, })) } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 931e91e9c79..2ad3d3a6d64 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -1093,7 +1093,9 @@ impl<'a> State<'a> { self.s.word("_")?; } ast::TyKind::Err => { - self.s.word("?")?; + self.popen()?; + self.s.word("/*ERROR*/")?; + self.pclose()?; } ast::TyKind::ImplicitSelf => { self.s.word("Self")?; @@ -2391,6 +2393,11 @@ impl<'a> State<'a> { self.s.space()?; self.print_block_with_attrs(blk, attrs)? } + ast::ExprKind::Err => { + self.popen()?; + self.s.word("/*ERROR*/")?; + self.pclose()? + } } self.ann.post(self, AnnNode::Expr(expr))?; self.end() diff --git a/src/libsyntax/util/parser.rs b/src/libsyntax/util/parser.rs index 52390fa5b1d..89d4e53b8d1 100644 --- a/src/libsyntax/util/parser.rs +++ b/src/libsyntax/util/parser.rs @@ -267,6 +267,7 @@ pub enum ExprPrecedence { TryBlock, Struct, Async, + Err, } impl ExprPrecedence { @@ -325,7 +326,8 @@ impl ExprPrecedence { ExprPrecedence::Block | ExprPrecedence::TryBlock | ExprPrecedence::Async | - ExprPrecedence::Struct => PREC_PAREN, + ExprPrecedence::Struct | + ExprPrecedence::Err => PREC_PAREN, } } } diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index 43f8a13609e..156546bbba9 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -802,6 +802,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) { ExprKind::TryBlock(ref body) => { visitor.visit_block(body) } + ExprKind::Err => {} } visitor.visit_expr_post(expression) |
