Skip to content

Commit b9f7197

Browse files
authored
Rollup merge of rust-lang#91519 - petrochenkov:cratexp2, r=Aaron1011
ast: Avoid aborts on fatal errors thrown from mutable AST visitor Set the node to some dummy value and rethrow the error instead. When using the old aborting `visit_clobber` in `InvocationCollector::visit_crate` the next tests abort due to fatal errors: ``` ui\modules\path-invalid-form.rs ui\modules\path-macro.rs ui\modules\path-no-file-name.rs ui\parser\issues\issue-5806.rs ui\parser\mod_file_with_path_attr.rs ``` Follow up to rust-lang#91313.
2 parents 65d8785 + bdb851f commit b9f7197

File tree

2 files changed

+127
-21
lines changed

2 files changed

+127
-21
lines changed

compiler/rustc_ast/src/mut_visit.rs

+116-12
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@ use crate::tokenstream::*;
1414

1515
use rustc_data_structures::map_in_place::MapInPlace;
1616
use rustc_data_structures::sync::Lrc;
17+
use rustc_data_structures::thin_vec::ThinVec;
1718
use rustc_span::source_map::Spanned;
1819
use rustc_span::symbol::Ident;
1920
use rustc_span::Span;
2021

2122
use smallvec::{smallvec, Array, SmallVec};
2223
use std::ops::DerefMut;
23-
use std::{panic, process, ptr};
24+
use std::{panic, ptr};
2425

2526
pub trait ExpectOne<A: Array> {
2627
fn expect_one(self, err: &'static str) -> A::Item;
@@ -283,23 +284,21 @@ pub trait MutVisitor: Sized {
283284

284285
/// Use a map-style function (`FnOnce(T) -> T`) to overwrite a `&mut T`. Useful
285286
/// when using a `flat_map_*` or `filter_map_*` method within a `visit_`
286-
/// method. Abort the program if the closure panics.
287-
///
288-
/// FIXME: Abort on panic means that any fatal error inside `visit_clobber` will abort the compiler.
289-
/// Instead of aborting on catching a panic we need to reset the visited node to some valid but
290-
/// possibly meaningless value and rethrow the panic.
287+
/// method.
291288
//
292289
// No `noop_` prefix because there isn't a corresponding method in `MutVisitor`.
293-
pub fn visit_clobber<T, F>(t: &mut T, f: F)
294-
where
295-
F: FnOnce(T) -> T,
296-
{
290+
pub fn visit_clobber<T: DummyAstNode>(t: &mut T, f: impl FnOnce(T) -> T) {
297291
unsafe {
298292
// Safe because `t` is used in a read-only fashion by `read()` before
299293
// being overwritten by `write()`.
300294
let old_t = ptr::read(t);
301-
let new_t = panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t)))
302-
.unwrap_or_else(|_| process::abort());
295+
let new_t =
296+
panic::catch_unwind(panic::AssertUnwindSafe(|| f(old_t))).unwrap_or_else(|err| {
297+
// Set `t` to some valid but possible meaningless value,
298+
// and pass the fatal error further.
299+
ptr::write(t, T::dummy());
300+
panic::resume_unwind(err);
301+
});
303302
ptr::write(t, new_t);
304303
}
305304
}
@@ -1454,3 +1453,108 @@ pub fn noop_visit_vis<T: MutVisitor>(visibility: &mut Visibility, vis: &mut T) {
14541453
}
14551454
vis.visit_span(&mut visibility.span);
14561455
}
1456+
1457+
/// Some value for the AST node that is valid but possibly meaningless.
1458+
pub trait DummyAstNode {
1459+
fn dummy() -> Self;
1460+
}
1461+
1462+
impl<T> DummyAstNode for Option<T> {
1463+
fn dummy() -> Self {
1464+
Default::default()
1465+
}
1466+
}
1467+
1468+
impl<T: DummyAstNode + 'static> DummyAstNode for P<T> {
1469+
fn dummy() -> Self {
1470+
P(DummyAstNode::dummy())
1471+
}
1472+
}
1473+
1474+
impl<T> DummyAstNode for ThinVec<T> {
1475+
fn dummy() -> Self {
1476+
Default::default()
1477+
}
1478+
}
1479+
1480+
impl DummyAstNode for Item {
1481+
fn dummy() -> Self {
1482+
Item {
1483+
attrs: Default::default(),
1484+
id: DUMMY_NODE_ID,
1485+
span: Default::default(),
1486+
vis: Visibility {
1487+
kind: VisibilityKind::Public,
1488+
span: Default::default(),
1489+
tokens: Default::default(),
1490+
},
1491+
ident: Ident::empty(),
1492+
kind: ItemKind::ExternCrate(None),
1493+
tokens: Default::default(),
1494+
}
1495+
}
1496+
}
1497+
1498+
impl DummyAstNode for Expr {
1499+
fn dummy() -> Self {
1500+
Expr {
1501+
id: DUMMY_NODE_ID,
1502+
kind: ExprKind::Err,
1503+
span: Default::default(),
1504+
attrs: Default::default(),
1505+
tokens: Default::default(),
1506+
}
1507+
}
1508+
}
1509+
1510+
impl DummyAstNode for Ty {
1511+
fn dummy() -> Self {
1512+
Ty {
1513+
id: DUMMY_NODE_ID,
1514+
kind: TyKind::Err,
1515+
span: Default::default(),
1516+
tokens: Default::default(),
1517+
}
1518+
}
1519+
}
1520+
1521+
impl DummyAstNode for Pat {
1522+
fn dummy() -> Self {
1523+
Pat {
1524+
id: DUMMY_NODE_ID,
1525+
kind: PatKind::Wild,
1526+
span: Default::default(),
1527+
tokens: Default::default(),
1528+
}
1529+
}
1530+
}
1531+
1532+
impl DummyAstNode for Stmt {
1533+
fn dummy() -> Self {
1534+
Stmt { id: DUMMY_NODE_ID, kind: StmtKind::Empty, span: Default::default() }
1535+
}
1536+
}
1537+
1538+
impl DummyAstNode for Block {
1539+
fn dummy() -> Self {
1540+
Block {
1541+
stmts: Default::default(),
1542+
id: DUMMY_NODE_ID,
1543+
rules: BlockCheckMode::Default,
1544+
span: Default::default(),
1545+
tokens: Default::default(),
1546+
could_be_bare_literal: Default::default(),
1547+
}
1548+
}
1549+
}
1550+
1551+
impl DummyAstNode for Crate {
1552+
fn dummy() -> Self {
1553+
Crate {
1554+
attrs: Default::default(),
1555+
items: Default::default(),
1556+
span: Default::default(),
1557+
is_placeholder: Default::default(),
1558+
}
1559+
}
1560+
}

compiler/rustc_expand/src/expand.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -1160,13 +1160,18 @@ macro_rules! assign_id {
11601160

11611161
impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11621162
fn visit_crate(&mut self, krate: &mut ast::Crate) {
1163-
let span = krate.span;
1164-
let empty_crate =
1165-
|| ast::Crate { attrs: Vec::new(), items: Vec::new(), span, is_placeholder: None };
1166-
let mut fold_crate = |krate: ast::Crate| {
1163+
visit_clobber(krate, |krate| {
1164+
let span = krate.span;
11671165
let mut krate = match self.configure(krate) {
11681166
Some(krate) => krate,
1169-
None => return empty_crate(),
1167+
None => {
1168+
return ast::Crate {
1169+
attrs: Vec::new(),
1170+
items: Vec::new(),
1171+
span,
1172+
is_placeholder: None,
1173+
};
1174+
}
11701175
};
11711176

11721177
if let Some(attr) = self.take_first_attr(&mut krate) {
@@ -1177,10 +1182,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> {
11771182

11781183
noop_visit_crate(&mut krate, self);
11791184
krate
1180-
};
1181-
1182-
// Cannot use `visit_clobber` here, see the FIXME on it.
1183-
*krate = fold_crate(mem::replace(krate, empty_crate()));
1185+
})
11841186
}
11851187

11861188
fn visit_expr(&mut self, expr: &mut P<ast::Expr>) {

0 commit comments

Comments
 (0)