Skip to content

Commit 5526682

Browse files
committed
Auto merge of #117330 - tmiasko:custom-mir-cleanup-blocks, r=cjgillot
Custom MIR: Support cleanup blocks Cleanup blocks are declared with `bb (cleanup) = { ... }`. `Call` and `Drop` terminators take an additional argument describing the unwind action, which is one of the following: * `UnwindContinue()` * `UnwindUnreachable()` * `UnwindTerminate(reason)`, where reason is `ReasonAbi` or `ReasonInCleanup` * `UnwindCleanup(block)` Also support unwind resume and unwind terminate terminators: * `UnwindResume()` * `UnwindTerminate(reason)`
2 parents 173b6e6 + 78da577 commit 5526682

38 files changed

+428
-107
lines changed

compiler/rustc_mir_build/src/build/custom/mod.rs

+13
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,19 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
162162
expected: expected.to_string(),
163163
}
164164
}
165+
166+
fn stmt_error(&self, stmt: StmtId, expected: &'static str) -> ParseError {
167+
let stmt = &self.thir[stmt];
168+
let span = match stmt.kind {
169+
StmtKind::Expr { expr, .. } => self.thir[expr].span,
170+
StmtKind::Let { span, .. } => span,
171+
};
172+
ParseError {
173+
span,
174+
item_description: format!("{:?}", stmt.kind),
175+
expected: expected.to_string(),
176+
}
177+
}
165178
}
166179

167180
type PResult<T> = Result<T, ParseError>;

compiler/rustc_mir_build/src/build/custom/parse.rs

+36-12
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@ macro_rules! parse_by_kind {
2727
$expr_name:pat,
2828
$expected:literal,
2929
$(
30-
@call($name:literal, $args:ident) => $call_expr:expr,
30+
@call($name:ident, $args:ident) => $call_expr:expr,
3131
)*
3232
$(
33-
$pat:pat => $expr:expr,
33+
@variant($adt:ident, $variant:ident) => $variant_expr:expr,
34+
)*
35+
$(
36+
$pat:pat $(if $guard:expr)? => $expr:expr,
3437
)*
3538
) => {{
3639
let expr_id = $self.preparse($expr_id);
@@ -42,14 +45,20 @@ macro_rules! parse_by_kind {
4245
ExprKind::Call { ty, fun: _, args: $args, .. } if {
4346
match ty.kind() {
4447
ty::FnDef(did, _) => {
45-
$self.tcx.is_diagnostic_item(rustc_span::Symbol::intern($name), *did)
48+
$self.tcx.is_diagnostic_item(rustc_span::sym::$name, *did)
4649
}
4750
_ => false,
4851
}
4952
} => $call_expr,
5053
)*
5154
$(
52-
$pat => $expr,
55+
ExprKind::Adt(box AdtExpr { adt_def, variant_index, .. }) if {
56+
$self.tcx.is_diagnostic_item(rustc_span::sym::$adt, adt_def.did()) &&
57+
adt_def.variants()[*variant_index].name == rustc_span::sym::$variant
58+
} => $variant_expr,
59+
)*
60+
$(
61+
$pat $(if $guard)? => $expr,
5362
)*
5463
#[allow(unreachable_patterns)]
5564
_ => return Err($self.expr_error(expr_id, $expected))
@@ -172,7 +181,8 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
172181
ExprKind::Block { block } => &self.thir[*block].stmts,
173182
);
174183
for (i, block_def) in block_defs.iter().enumerate() {
175-
let block = self.parse_block_def(self.statement_as_expr(*block_def)?)?;
184+
let is_cleanup = self.body.basic_blocks_mut()[BasicBlock::from_usize(i)].is_cleanup;
185+
let block = self.parse_block_def(self.statement_as_expr(*block_def)?, is_cleanup)?;
176186
self.body.basic_blocks_mut()[BasicBlock::from_usize(i)] = block;
177187
}
178188

@@ -181,15 +191,28 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
181191

182192
fn parse_block_decls(&mut self, stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
183193
for stmt in stmts {
184-
let (var, _, _) = self.parse_let_statement(stmt)?;
185-
let data = BasicBlockData::new(None);
186-
let block = self.body.basic_blocks_mut().push(data);
187-
self.block_map.insert(var, block);
194+
self.parse_basic_block_decl(stmt)?;
188195
}
189-
190196
Ok(())
191197
}
192198

199+
fn parse_basic_block_decl(&mut self, stmt: StmtId) -> PResult<()> {
200+
match &self.thir[stmt].kind {
201+
StmtKind::Let { pattern, initializer: Some(initializer), .. } => {
202+
let (var, ..) = self.parse_var(pattern)?;
203+
let mut data = BasicBlockData::new(None);
204+
data.is_cleanup = parse_by_kind!(self, *initializer, _, "basic block declaration",
205+
@variant(mir_basic_block, Normal) => false,
206+
@variant(mir_basic_block, Cleanup) => true,
207+
);
208+
let block = self.body.basic_blocks_mut().push(data);
209+
self.block_map.insert(var, block);
210+
Ok(())
211+
}
212+
_ => Err(self.stmt_error(stmt, "let statement with an initializer")),
213+
}
214+
}
215+
193216
fn parse_local_decls(&mut self, mut stmts: impl Iterator<Item = StmtId>) -> PResult<()> {
194217
let (ret_var, ..) = self.parse_let_statement(stmts.next().unwrap())?;
195218
self.local_map.insert(ret_var, Local::from_u32(0));
@@ -219,7 +242,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
219242
};
220243
let span = self.thir[expr].span;
221244
let (name, operand) = parse_by_kind!(self, expr, _, "debuginfo",
222-
@call("mir_debuginfo", args) => {
245+
@call(mir_debuginfo, args) => {
223246
(args[0], args[1])
224247
},
225248
);
@@ -281,12 +304,13 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
281304
}
282305
}
283306

284-
fn parse_block_def(&self, expr_id: ExprId) -> PResult<BasicBlockData<'tcx>> {
307+
fn parse_block_def(&self, expr_id: ExprId, is_cleanup: bool) -> PResult<BasicBlockData<'tcx>> {
285308
let block = parse_by_kind!(self, expr_id, _, "basic block",
286309
ExprKind::Block { block } => &self.thir[*block],
287310
);
288311

289312
let mut data = BasicBlockData::new(None);
313+
data.is_cleanup = is_cleanup;
290314
for stmt_id in &*block.stmts {
291315
let stmt = self.statement_as_expr(*stmt_id)?;
292316
let span = self.thir[stmt].span;

compiler/rustc_mir_build/src/build/custom/parse/instruction.rs

+59-24
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,19 @@ use super::{parse_by_kind, PResult, ParseCtxt};
1313
impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
1414
pub fn parse_statement(&self, expr_id: ExprId) -> PResult<StatementKind<'tcx>> {
1515
parse_by_kind!(self, expr_id, _, "statement",
16-
@call("mir_storage_live", args) => {
16+
@call(mir_storage_live, args) => {
1717
Ok(StatementKind::StorageLive(self.parse_local(args[0])?))
1818
},
19-
@call("mir_storage_dead", args) => {
19+
@call(mir_storage_dead, args) => {
2020
Ok(StatementKind::StorageDead(self.parse_local(args[0])?))
2121
},
22-
@call("mir_deinit", args) => {
22+
@call(mir_deinit, args) => {
2323
Ok(StatementKind::Deinit(Box::new(self.parse_place(args[0])?)))
2424
},
25-
@call("mir_retag", args) => {
25+
@call(mir_retag, args) => {
2626
Ok(StatementKind::Retag(RetagKind::Default, Box::new(self.parse_place(args[0])?)))
2727
},
28-
@call("mir_set_discriminant", args) => {
28+
@call(mir_set_discriminant, args) => {
2929
let place = self.parse_place(args[0])?;
3030
let var = self.parse_integer_literal(args[1])? as u32;
3131
Ok(StatementKind::SetDiscriminant {
@@ -43,24 +43,30 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
4343

4444
pub fn parse_terminator(&self, expr_id: ExprId) -> PResult<TerminatorKind<'tcx>> {
4545
parse_by_kind!(self, expr_id, expr, "terminator",
46-
@call("mir_return", _args) => {
46+
@call(mir_return, _args) => {
4747
Ok(TerminatorKind::Return)
4848
},
49-
@call("mir_goto", args) => {
49+
@call(mir_goto, args) => {
5050
Ok(TerminatorKind::Goto { target: self.parse_block(args[0])? } )
5151
},
52-
@call("mir_unreachable", _args) => {
52+
@call(mir_unreachable, _args) => {
5353
Ok(TerminatorKind::Unreachable)
5454
},
55-
@call("mir_drop", args) => {
55+
@call(mir_unwind_resume, _args) => {
56+
Ok(TerminatorKind::UnwindResume)
57+
},
58+
@call(mir_unwind_terminate, args) => {
59+
Ok(TerminatorKind::UnwindTerminate(self.parse_unwind_terminate_reason(args[0])?))
60+
},
61+
@call(mir_drop, args) => {
5662
Ok(TerminatorKind::Drop {
5763
place: self.parse_place(args[0])?,
5864
target: self.parse_block(args[1])?,
59-
unwind: UnwindAction::Continue,
65+
unwind: self.parse_unwind_action(args[2])?,
6066
replace: false,
6167
})
6268
},
63-
@call("mir_call", args) => {
69+
@call(mir_call, args) => {
6470
self.parse_call(args)
6571
},
6672
ExprKind::Match { scrutinee, arms, .. } => {
@@ -70,6 +76,34 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
7076
)
7177
}
7278

79+
fn parse_unwind_terminate_reason(&self, expr_id: ExprId) -> PResult<UnwindTerminateReason> {
80+
parse_by_kind!(self, expr_id, _, "unwind terminate reason",
81+
@variant(mir_unwind_terminate_reason, Abi) => {
82+
Ok(UnwindTerminateReason::Abi)
83+
},
84+
@variant(mir_unwind_terminate_reason, InCleanup) => {
85+
Ok(UnwindTerminateReason::InCleanup)
86+
},
87+
)
88+
}
89+
90+
fn parse_unwind_action(&self, expr_id: ExprId) -> PResult<UnwindAction> {
91+
parse_by_kind!(self, expr_id, _, "unwind action",
92+
@call(mir_unwind_continue, _args) => {
93+
Ok(UnwindAction::Continue)
94+
},
95+
@call(mir_unwind_unreachable, _args) => {
96+
Ok(UnwindAction::Unreachable)
97+
},
98+
@call(mir_unwind_terminate, args) => {
99+
Ok(UnwindAction::Terminate(self.parse_unwind_terminate_reason(args[0])?))
100+
},
101+
@call(mir_unwind_cleanup, args) => {
102+
Ok(UnwindAction::Cleanup(self.parse_block(args[0])?))
103+
},
104+
)
105+
}
106+
73107
fn parse_match(&self, arms: &[ArmId], span: Span) -> PResult<SwitchTargets> {
74108
let Some((otherwise, rest)) = arms.split_last() else {
75109
return Err(ParseError {
@@ -113,6 +147,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
113147
);
114148
let destination = self.parse_place(destination)?;
115149
let target = self.parse_block(args[1])?;
150+
let unwind = self.parse_unwind_action(args[2])?;
116151

117152
parse_by_kind!(self, call, _, "function call",
118153
ExprKind::Call { fun, args, from_hir_call, fn_span, .. } => {
@@ -126,7 +161,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
126161
args,
127162
destination,
128163
target: Some(target),
129-
unwind: UnwindAction::Continue,
164+
unwind,
130165
call_source: if *from_hir_call { CallSource::Normal } else {
131166
CallSource::OverloadedOperator
132167
},
@@ -138,25 +173,25 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
138173

139174
fn parse_rvalue(&self, expr_id: ExprId) -> PResult<Rvalue<'tcx>> {
140175
parse_by_kind!(self, expr_id, expr, "rvalue",
141-
@call("mir_discriminant", args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
142-
@call("mir_cast_transmute", args) => {
176+
@call(mir_discriminant, args) => self.parse_place(args[0]).map(Rvalue::Discriminant),
177+
@call(mir_cast_transmute, args) => {
143178
let source = self.parse_operand(args[0])?;
144179
Ok(Rvalue::Cast(CastKind::Transmute, source, expr.ty))
145180
},
146-
@call("mir_checked", args) => {
181+
@call(mir_checked, args) => {
147182
parse_by_kind!(self, args[0], _, "binary op",
148183
ExprKind::Binary { op, lhs, rhs } => Ok(Rvalue::CheckedBinaryOp(
149184
*op, Box::new((self.parse_operand(*lhs)?, self.parse_operand(*rhs)?))
150185
)),
151186
)
152187
},
153-
@call("mir_offset", args) => {
188+
@call(mir_offset, args) => {
154189
let ptr = self.parse_operand(args[0])?;
155190
let offset = self.parse_operand(args[1])?;
156191
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
157192
},
158-
@call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
159-
@call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
193+
@call(mir_len, args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
194+
@call(mir_copy_for_deref, args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
160195
ExprKind::Borrow { borrow_kind, arg } => Ok(
161196
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
162197
),
@@ -206,9 +241,9 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
206241

207242
pub fn parse_operand(&self, expr_id: ExprId) -> PResult<Operand<'tcx>> {
208243
parse_by_kind!(self, expr_id, expr, "operand",
209-
@call("mir_move", args) => self.parse_place(args[0]).map(Operand::Move),
210-
@call("mir_static", args) => self.parse_static(args[0]),
211-
@call("mir_static_mut", args) => self.parse_static(args[0]),
244+
@call(mir_move, args) => self.parse_place(args[0]).map(Operand::Move),
245+
@call(mir_static, args) => self.parse_static(args[0]),
246+
@call(mir_static_mut, args) => self.parse_static(args[0]),
212247
ExprKind::Literal { .. }
213248
| ExprKind::NamedConst { .. }
214249
| ExprKind::NonHirLiteral { .. }
@@ -229,23 +264,23 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
229264

230265
fn parse_place_inner(&self, expr_id: ExprId) -> PResult<(Place<'tcx>, PlaceTy<'tcx>)> {
231266
let (parent, proj) = parse_by_kind!(self, expr_id, expr, "place",
232-
@call("mir_field", args) => {
267+
@call(mir_field, args) => {
233268
let (parent, ty) = self.parse_place_inner(args[0])?;
234269
let field = FieldIdx::from_u32(self.parse_integer_literal(args[1])? as u32);
235270
let field_ty = ty.field_ty(self.tcx, field);
236271
let proj = PlaceElem::Field(field, field_ty);
237272
let place = parent.project_deeper(&[proj], self.tcx);
238273
return Ok((place, PlaceTy::from_ty(field_ty)));
239274
},
240-
@call("mir_variant", args) => {
275+
@call(mir_variant, args) => {
241276
(args[0], PlaceElem::Downcast(
242277
None,
243278
VariantIdx::from_u32(self.parse_integer_literal(args[1])? as u32)
244279
))
245280
},
246281
ExprKind::Deref { arg } => {
247282
parse_by_kind!(self, *arg, _, "does not matter",
248-
@call("mir_make_place", args) => return self.parse_place_inner(args[0]),
283+
@call(mir_make_place, args) => return self.parse_place_inner(args[0]),
249284
_ => (*arg, PlaceElem::Deref),
250285
)
251286
},

compiler/rustc_span/src/symbol.rs

+34
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ symbols! {
124124
// There is currently no checking that all symbols are used; that would be
125125
// nice to have.
126126
Symbols {
127+
Abi,
127128
AcqRel,
128129
Acquire,
129130
AddToDiagnostic,
@@ -166,6 +167,7 @@ symbols! {
166167
CString,
167168
Capture,
168169
Center,
170+
Cleanup,
169171
Clone,
170172
Command,
171173
ConstParamTy,
@@ -215,6 +217,7 @@ symbols! {
215217
HashSet,
216218
Hasher,
217219
Implied,
220+
InCleanup,
218221
IndexOutput,
219222
Input,
220223
Instant,
@@ -258,6 +261,7 @@ symbols! {
258261
NonZeroU8,
259262
NonZeroUsize,
260263
None,
264+
Normal,
261265
Ok,
262266
Option,
263267
Ord,
@@ -1023,6 +1027,36 @@ symbols! {
10231027
minnumf32,
10241028
minnumf64,
10251029
mips_target_feature,
1030+
mir_basic_block,
1031+
mir_call,
1032+
mir_cast_transmute,
1033+
mir_checked,
1034+
mir_copy_for_deref,
1035+
mir_debuginfo,
1036+
mir_deinit,
1037+
mir_discriminant,
1038+
mir_drop,
1039+
mir_field,
1040+
mir_goto,
1041+
mir_len,
1042+
mir_make_place,
1043+
mir_move,
1044+
mir_offset,
1045+
mir_retag,
1046+
mir_return,
1047+
mir_set_discriminant,
1048+
mir_static,
1049+
mir_static_mut,
1050+
mir_storage_dead,
1051+
mir_storage_live,
1052+
mir_unreachable,
1053+
mir_unwind_cleanup,
1054+
mir_unwind_continue,
1055+
mir_unwind_resume,
1056+
mir_unwind_terminate,
1057+
mir_unwind_terminate_reason,
1058+
mir_unwind_unreachable,
1059+
mir_variant,
10261060
miri,
10271061
misc,
10281062
mmx_reg,

0 commit comments

Comments
 (0)