Skip to content

Commit

Permalink
Rollup merge of rust-lang#56999 - petrochenkov:macrecov2, r=estebank
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
Centril authored Dec 23, 2018
2 parents ae6164c + 4a6aa36 commit 677d8b5
Show file tree
Hide file tree
Showing 124 changed files with 711 additions and 365 deletions.
3 changes: 2 additions & 1 deletion src/librustc/cfg/construct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,8 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {

hir::ExprKind::Closure(..) |
hir::ExprKind::Lit(..) |
hir::ExprKind::Path(_) => {
hir::ExprKind::Path(_) |
hir::ExprKind::Err => {
self.straightline(expr, pred, None::<hir::Expr>.iter())
}
}
Expand Down
1 change: 1 addition & 0 deletions src/librustc/hir/intravisit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1109,6 +1109,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
ExprKind::Yield(ref subexpression) => {
visitor.visit_expr(subexpression);
}
ExprKind::Err => {}
}
}

Expand Down
5 changes: 2 additions & 3 deletions src/librustc/hir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2719,7 +2719,6 @@ impl<'a> LoweringContext<'a> {
rules: self.lower_block_check_mode(&b.rules),
span: b.span,
targeted_by_break,
recovered: b.recovered,
})
}

Expand Down Expand Up @@ -3791,7 +3790,6 @@ impl<'a> LoweringContext<'a> {
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
recovered: blk.recovered,
});
P(self.expr_block(blk, ThinVec::new()))
}
Expand Down Expand Up @@ -4127,6 +4125,8 @@ impl<'a> LoweringContext<'a> {
hir::ExprKind::Yield(P(expr))
}

ExprKind::Err => hir::ExprKind::Err,

// Desugar `ExprIfLet`
// from: `if let <pat> = <sub_expr> <body> [<else_opt>]`
ExprKind::IfLet(ref pats, ref sub_expr, ref body, ref else_opt) => {
Expand Down Expand Up @@ -4831,7 +4831,6 @@ impl<'a> LoweringContext<'a> {
rules: hir::DefaultBlock,
span,
targeted_by_break: false,
recovered: false,
}
}

Expand Down
12 changes: 6 additions & 6 deletions src/librustc/hir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -817,11 +817,6 @@ pub struct Block {
/// break out of this block early.
/// Used by `'label: {}` blocks and by `catch` statements.
pub targeted_by_break: bool,
/// If true, don't emit return value type errors as the parser had
/// to recover from a parse error so this block will not have an
/// appropriate type. A parse error will have been emitted so the
/// compilation will never succeed if this is true.
pub recovered: bool,
}

#[derive(Clone, RustcEncodable, RustcDecodable)]
Expand Down Expand Up @@ -1372,6 +1367,7 @@ impl Expr {
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Yield(..) => ExprPrecedence::Yield,
ExprKind::Err => ExprPrecedence::Err,
}
}

Expand Down Expand Up @@ -1422,7 +1418,8 @@ impl Expr {
ExprKind::AddrOf(..) |
ExprKind::Binary(..) |
ExprKind::Yield(..) |
ExprKind::Cast(..) => {
ExprKind::Cast(..) |
ExprKind::Err => {
false
}
}
Expand Down Expand Up @@ -1535,6 +1532,9 @@ pub enum ExprKind {

/// A suspension point for generators. This is `yield <expr>` in Rust.
Yield(P<Expr>),

/// Placeholder for an expression that wasn't syntactically well formed in some way.
Err,
}

/// Optionally `Self`-qualified value/type path or associated extension.
Expand Down
9 changes: 8 additions & 1 deletion src/librustc/hir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,9 @@ impl<'a> State<'a> {
self.s.word("_")?;
}
hir::TyKind::Err => {
self.s.word("?")?;
self.popen()?;
self.s.word("/*ERROR*/")?;
self.pclose()?;
}
}
self.end()
Expand Down Expand Up @@ -1550,6 +1552,11 @@ impl<'a> State<'a> {
self.word_space("yield")?;
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP)?;
}
hir::ExprKind::Err => {
self.popen()?;
self.s.word("/*ERROR*/")?;
self.pclose()?;
}
}
self.ann.post(self, AnnNode::Expr(expr))?;
self.end()
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ich/impls_hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -420,7 +420,6 @@ impl_stable_hash_for!(struct hir::Block {
rules,
span,
targeted_by_break,
recovered,
});

impl_stable_hash_for!(struct hir::Pat {
Expand Down Expand Up @@ -602,7 +601,8 @@ impl_stable_hash_for!(enum hir::ExprKind {
InlineAsm(asm, inputs, outputs),
Struct(path, fields, base),
Repeat(val, times),
Yield(val)
Yield(val),
Err
});

impl_stable_hash_for!(enum hir::LocalSource {
Expand Down
6 changes: 2 additions & 4 deletions src/librustc/lint/levels.rs
Original file line number Diff line number Diff line change
Expand Up @@ -232,24 +232,22 @@ impl<'a> LintLevelsBuilder<'a> {
match item.node {
ast::MetaItemKind::Word => {} // actual lint names handled later
ast::MetaItemKind::NameValue(ref name_value) => {
let gate_reasons = !self.sess.features_untracked().lint_reasons;
if item.ident == "reason" {
// found reason, reslice meta list to exclude it
metas = &metas[0..metas.len()-1];
// FIXME (#55112): issue unused-attributes lint if we thereby
// don't have any lint names (`#[level(reason = "foo")]`)
if let ast::LitKind::Str(rationale, _) = name_value.node {
if gate_reasons {
if !self.sess.features_untracked().lint_reasons {
feature_gate::emit_feature_err(
&self.sess.parse_sess,
"lint_reasons",
item.span,
feature_gate::GateIssue::Language,
"lint reasons are experimental"
);
} else {
reason = Some(rationale);
}
reason = Some(rationale);
} else {
let mut err = bad_attr(name_value.span);
err.help("reason must be a string literal");
Expand Down
3 changes: 2 additions & 1 deletion src/librustc/middle/expr_use_visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,8 @@ impl<'a, 'gcx, 'tcx> ExprUseVisitor<'a, 'gcx, 'tcx> {
}

hir::ExprKind::Continue(..) |
hir::ExprKind::Lit(..) => {}
hir::ExprKind::Lit(..) |
hir::ExprKind::Err => {}

hir::ExprKind::Loop(ref blk, _, _) => {
self.walk_block(&blk);
Expand Down
6 changes: 4 additions & 2 deletions src/librustc/middle/liveness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -525,6 +525,7 @@ fn visit_expr<'a, 'tcx>(ir: &mut IrMaps<'a, 'tcx>, expr: &'tcx Expr) {
hir::ExprKind::Box(..) |
hir::ExprKind::Yield(..) |
hir::ExprKind::Type(..) |
hir::ExprKind::Err |
hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
intravisit::walk_expr(ir, expr);
}
Expand Down Expand Up @@ -1264,7 +1265,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.propagate_through_exprs(inputs, succ)
}

hir::ExprKind::Lit(..) | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
hir::ExprKind::Lit(..) | hir::ExprKind::Err |
hir::ExprKind::Path(hir::QPath::TypeRelative(..)) => {
succ
}

Expand Down Expand Up @@ -1531,7 +1533,7 @@ fn check_expr<'a, 'tcx>(this: &mut Liveness<'a, 'tcx>, expr: &'tcx Expr) {
hir::ExprKind::Block(..) | hir::ExprKind::AddrOf(..) |
hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
hir::ExprKind::Closure(..) | hir::ExprKind::Path(_) | hir::ExprKind::Yield(..) |
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) => {
hir::ExprKind::Box(..) | hir::ExprKind::Type(..) | hir::ExprKind::Err => {
intravisit::walk_expr(this, expr);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {
hir::ExprKind::Block(..) | hir::ExprKind::Loop(..) | hir::ExprKind::Match(..) |
hir::ExprKind::Lit(..) | hir::ExprKind::Break(..) |
hir::ExprKind::Continue(..) | hir::ExprKind::Struct(..) | hir::ExprKind::Repeat(..) |
hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) => {
hir::ExprKind::InlineAsm(..) | hir::ExprKind::Box(..) | hir::ExprKind::Err => {
Ok(self.cat_rvalue_node(expr.hir_id, expr.span, expr_ty))
}
}
Expand Down
10 changes: 0 additions & 10 deletions src/librustc_driver/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -997,7 +997,6 @@ where
};

let mut ecx = ExtCtxt::new(&sess.parse_sess, cfg, &mut resolver);
let err_count = ecx.parse_sess.span_diagnostic.err_count();

// Expand macros now!
let krate = time(sess, "expand crate", || {
Expand All @@ -1023,9 +1022,6 @@ where
let msg = "missing fragment specifier";
sess.buffer_lint(lint, ast::CRATE_NODE_ID, span, msg);
}
if ecx.parse_sess.span_diagnostic.err_count() - ecx.resolve_err_count > err_count {
ecx.parse_sess.span_diagnostic.abort_if_errors();
}
if cfg!(windows) {
env::set_var("PATH", &old_path);
}
Expand Down Expand Up @@ -1129,12 +1125,6 @@ where
})
})?;

// Unresolved macros might be due to mistyped `#[macro_use]`,
// so abort after checking for unknown attributes. (#49074)
if resolver.found_unresolved_macro {
sess.diagnostic().abort_if_errors();
}

// Lower ast -> hir.
// First, we need to collect the dep_graph.
let dep_graph = match future_dep_graph {
Expand Down
6 changes: 2 additions & 4 deletions src/librustc_driver/pretty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -751,15 +751,13 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {

fn fold_block(&mut self, b: P<ast::Block>) -> P<ast::Block> {
fn stmt_to_block(rules: ast::BlockCheckMode,
recovered: bool,
s: Option<ast::Stmt>,
sess: &Session) -> ast::Block {
ast::Block {
stmts: s.into_iter().collect(),
rules,
id: sess.next_node_id(),
span: syntax_pos::DUMMY_SP,
recovered,
}
}

Expand All @@ -778,7 +776,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
}
}

let empty_block = stmt_to_block(BlockCheckMode::Default, false, None, self.sess);
let empty_block = stmt_to_block(BlockCheckMode::Default, None, self.sess);
let loop_expr = P(ast::Expr {
node: ast::ExprKind::Loop(P(empty_block), None),
id: self.sess.next_node_id(),
Expand Down Expand Up @@ -819,7 +817,7 @@ impl<'a> fold::Folder for ReplaceBodyWithLoop<'a> {
old_blocks.push(new_block);
}

stmt_to_block(b.rules, b.recovered, Some(loop_stmt), self.sess)
stmt_to_block(b.rules, Some(loop_stmt), self.sess)
} else {
//push `loop {}` onto the end of our fresh block and yield that
new_block.stmts.push(loop_stmt);
Expand Down
1 change: 1 addition & 0 deletions src/librustc_mir/hair/cx/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -790,6 +790,7 @@ fn make_mirror_unadjusted<'a, 'gcx, 'tcx>(cx: &mut Cx<'a, 'gcx, 'tcx>,
hir::ExprKind::Tup(ref fields) => ExprKind::Tuple { fields: fields.to_ref() },

hir::ExprKind::Yield(ref v) => ExprKind::Yield { value: v.to_ref() },
hir::ExprKind::Err => unreachable!(),
};

Expr {
Expand Down
30 changes: 0 additions & 30 deletions src/librustc_passes/ast_validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,25 +288,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_ty(self, ty)
}

fn visit_use_tree(&mut self, use_tree: &'a UseTree, id: NodeId, _nested: bool) {
// Check if the path in this `use` is not generic, such as `use foo::bar<T>;` While this
// can't happen normally thanks to the parser, a generic might sneak in if the `use` is
// built using a macro.
//
// macro_use foo {
// ($p:path) => { use $p; }
// }
// foo!(bar::baz<T>);
use_tree.prefix.segments.iter().find(|segment| {
segment.args.is_some()
}).map(|segment| {
self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
"generic arguments in import path");
});

visit::walk_use_tree(self, use_tree, id);
}

fn visit_label(&mut self, label: &'a Label) {
self.check_label(label.ident);
visit::walk_label(self, label);
Expand Down Expand Up @@ -443,17 +424,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
visit::walk_foreign_item(self, fi)
}

fn visit_vis(&mut self, vis: &'a Visibility) {
if let VisibilityKind::Restricted { ref path, .. } = vis.node {
path.segments.iter().find(|segment| segment.args.is_some()).map(|segment| {
self.err_handler().span_err(segment.args.as_ref().unwrap().span(),
"generic arguments in visibility path");
});
}

visit::walk_vis(self, vis)
}

fn visit_generics(&mut self, generics: &'a Generics) {
let mut seen_non_lifetime_param = false;
let mut seen_default = None;
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_passes/rvalue_promotion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -459,7 +459,8 @@ fn check_expr_kind<'a, 'tcx>(
struct_result
}

hir::ExprKind::Lit(_) => Promotable,
hir::ExprKind::Lit(_) |
hir::ExprKind::Err => Promotable,

hir::ExprKind::AddrOf(_, ref expr) |
hir::ExprKind::Repeat(ref expr, _) => {
Expand Down
7 changes: 4 additions & 3 deletions src/librustc_resolve/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1584,7 +1584,6 @@ pub struct Resolver<'a> {
macro_map: FxHashMap<DefId, Lrc<SyntaxExtension>>,
macro_defs: FxHashMap<Mark, DefId>,
local_macro_def_scopes: FxHashMap<NodeId, Module<'a>>,
pub found_unresolved_macro: bool,

/// List of crate local macros that we need to warn about as being unused.
/// Right now this only includes macro_rules! macros, and macros 2.0.
Expand Down Expand Up @@ -1919,7 +1918,6 @@ impl<'a> Resolver<'a> {
name_already_seen: FxHashMap::default(),
potentially_unused_imports: Vec::new(),
struct_constructors: Default::default(),
found_unresolved_macro: false,
unused_macros: FxHashSet::default(),
current_type_ascription: Vec::new(),
injected_crate: None,
Expand Down Expand Up @@ -2032,8 +2030,10 @@ impl<'a> Resolver<'a> {
record_used_id: Option<NodeId>,
path_span: Span)
-> Option<LexicalScopeBinding<'a>> {
let record_used = record_used_id.is_some();
assert!(ns == TypeNS || ns == ValueNS);
if ident.name == keywords::Invalid.name() {
return Some(LexicalScopeBinding::Def(Def::Err));
}
if ns == TypeNS {
ident.span = if ident.name == keywords::SelfUpper.name() {
// FIXME(jseyfried) improve `Self` hygiene
Expand All @@ -2046,6 +2046,7 @@ impl<'a> Resolver<'a> {
}

// Walk backwards up the ribs in scope.
let record_used = record_used_id.is_some();
let mut module = self.graph_root;
for i in (0 .. self.ribs[ns].len()).rev() {
if let Some(def) = self.ribs[ns][i].bindings.get(&ident).cloned() {
Expand Down
Loading

0 comments on commit 677d8b5

Please sign in to comment.