@@ -105,13 +105,34 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
105
105
106
106
impl < ' a > ExactSizeIterator for SwitchTargetsIter < ' a > { }
107
107
108
+ /// A note on unwinding: Panics may occur during the execution of some terminators. Depending on the
109
+ /// `-C panic` flag, this may either cause the program to abort or the call stack to unwind. Such
110
+ /// terminators have a `cleanup: Option<BasicBlock>` field on them. If stack unwinding occurs, then
111
+ /// once the current function is reached, execution continues at the given basic block, if any. If
112
+ /// `cleanup` is `None` then no cleanup is performed, and the stack continues unwinding. This is
113
+ /// equivalent to the execution of a `Resume` terminator.
114
+ ///
115
+ /// The basic block pointed to by a `cleanup` field must have its `cleanup` flag set. `cleanup`
116
+ /// basic blocks have a couple restrictions:
117
+ /// 1. All `cleanup` fields in them must be `None`.
118
+ /// 2. `Return` terminators are not allowed in them. `Abort` and `Unwind` terminators are.
119
+ /// 3. All other basic blocks (in the current body) that are reachable from `cleanup` basic blocks
120
+ /// must also be `cleanup`. This is a part of the type system and checked statically, so it is
121
+ /// still an error to have such an edge in the CFG even if it's known that it won't be taken at
122
+ /// runtime.
108
123
#[ derive( Clone , TyEncodable , TyDecodable , Hash , HashStable , PartialEq ) ]
109
124
pub enum TerminatorKind < ' tcx > {
110
- /// Block should have one successor in the graph ; we jump there.
125
+ /// Block has one successor; we continue execution there.
111
126
Goto { target : BasicBlock } ,
112
127
113
- /// Operand evaluates to an integer; jump depending on its value
114
- /// to one of the targets, and otherwise fallback to `otherwise`.
128
+ /// Switches based on the computed value.
129
+ ///
130
+ /// First, evaluates the `discr` operand. The type of the operand must be a signed or unsigned
131
+ /// integer, char, or bool, and must match the given type. Then, if the list of switch targets
132
+ /// contains the computed value, continues execution at the associated basic block. Otherwise,
133
+ /// continues execution at the "otherwise" basic block.
134
+ ///
135
+ /// Target values may not appear more than once.
115
136
SwitchInt {
116
137
/// The discriminant value being tested.
117
138
discr : Operand < ' tcx > ,
@@ -124,29 +145,62 @@ pub enum TerminatorKind<'tcx> {
124
145
targets : SwitchTargets ,
125
146
} ,
126
147
127
- /// Indicates that the landing pad is finished and unwinding should
128
- /// continue. Emitted by `build::scope::diverge_cleanup`.
148
+ /// Indicates that the landing pad is finished and that the process should continue unwinding.
149
+ ///
150
+ /// Like a return, this marks the end of this invocation of the function.
151
+ ///
152
+ /// Only permitted in cleanup blocks. `Resume` is not permitted with `-C unwind=abort` after
153
+ /// deaggregation runs.
129
154
Resume ,
130
155
131
- /// Indicates that the landing pad is finished and that the process
132
- /// should abort. Used to prevent unwinding for foreign items.
156
+ /// Indicates that the landing pad is finished and that the process should abort.
157
+ ///
158
+ /// Used to prevent unwinding for foreign items or with `-C unwind=abort`. Only permitted in
159
+ /// cleanup blocks.
133
160
Abort ,
134
161
135
- /// Indicates a normal return. The return place should have
136
- /// been filled in before this executes. This can occur multiple times
137
- /// in different basic blocks.
162
+ /// Returns from the function.
163
+ ///
164
+ /// Like function calls, the exact semantics of returns in Rust are unclear. Returning very
165
+ /// likely at least assigns the value currently in the return place (`_0`) to the place
166
+ /// specified in the associated `Call` terminator in the calling function, as if assigned via
167
+ /// `dest = move _0`. It might additionally do other things, like have side-effects in the
168
+ /// aliasing model.
169
+ ///
170
+ /// If the body is a generator body, this has slightly different semantics; it instead causes a
171
+ /// `GeneratorState::Returned(_0)` to be created (as if by an `Aggregate` rvalue) and assigned
172
+ /// to the return place.
138
173
Return ,
139
174
140
175
/// Indicates a terminator that can never be reached.
176
+ ///
177
+ /// Executing this terminator is UB.
141
178
Unreachable ,
142
179
143
- /// Drop the `Place`.
180
+ /// The behavior of this statement differs significantly before and after drop elaboration.
181
+ /// After drop elaboration, `Drop` executes the drop glue for the specified place, after which
182
+ /// it continues execution/unwinds at the given basic blocks. It is possible that executing drop
183
+ /// glue is special - this would be part of Rust's memory model. (**FIXME**: due we have an
184
+ /// issue tracking if drop glue has any interesting semantics in addition to those of a function
185
+ /// call?)
186
+ ///
187
+ /// `Drop` before drop elaboration is a *conditional* execution of the drop glue. Specifically, the
188
+ /// `Drop` will be executed if...
189
+ ///
190
+ /// **Needs clarification**: End of that sentence. This in effect should document the exact
191
+ /// behavior of drop elaboration. The following sounds vaguely right, but I'm not quite sure:
192
+ ///
193
+ /// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
194
+ /// > the place or one of its "parents" occurred more recently than a move out of it. This does not
195
+ /// > consider indirect assignments.
144
196
Drop { place : Place < ' tcx > , target : BasicBlock , unwind : Option < BasicBlock > } ,
145
197
146
- /// Drop the `Place` and assign the new value over it. This ensures
147
- /// that the assignment to `P` occurs *even if* the destructor for
148
- /// place unwinds. Its semantics are best explained by the
149
- /// elaboration:
198
+ /// Drops the place and assigns a new value to it.
199
+ ///
200
+ /// This first performs the exact same operation as the pre drop-elaboration `Drop` terminator;
201
+ /// it then additionally assigns the `value` to the `place` as if by an assignment statement.
202
+ /// This assignment occurs both in the unwind and the regular code paths. The semantics are best
203
+ /// explained by the elaboration:
150
204
///
151
205
/// ```
152
206
/// BB0 {
@@ -170,15 +224,22 @@ pub enum TerminatorKind<'tcx> {
170
224
/// }
171
225
/// ```
172
226
///
173
- /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass .
227
+ /// Disallowed after drop elaboration .
174
228
DropAndReplace {
175
229
place : Place < ' tcx > ,
176
230
value : Operand < ' tcx > ,
177
231
target : BasicBlock ,
178
232
unwind : Option < BasicBlock > ,
179
233
} ,
180
234
181
- /// Block ends with a call of a function.
235
+ /// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
236
+ /// the referred to function. The operand types must match the argument types of the function.
237
+ /// The return place type must exactly match the return type. The type of the `func` operand
238
+ /// must be callable, meaning either a function pointer, a function type, or a closure type.
239
+ ///
240
+ /// **Needs clarification**: The exact semantics of this, see [#71117].
241
+ ///
242
+ /// [#71117]: https://github.com/rust-lang/rust/issues/71117
182
243
Call {
183
244
/// The function that’s being called.
184
245
func : Operand < ' tcx > ,
@@ -187,7 +248,7 @@ pub enum TerminatorKind<'tcx> {
187
248
/// This allows the memory occupied by "by-value" arguments to be
188
249
/// reused across function calls without duplicating the contents.
189
250
args : Vec < Operand < ' tcx > > ,
190
- /// Destination for the return value. If some , the call is converging .
251
+ /// Destination for the return value. If none , the call necessarily diverges .
191
252
destination : Option < ( Place < ' tcx > , BasicBlock ) > ,
192
253
/// Cleanups to be done if the call unwinds.
193
254
cleanup : Option < BasicBlock > ,
@@ -199,8 +260,12 @@ pub enum TerminatorKind<'tcx> {
199
260
fn_span : Span ,
200
261
} ,
201
262
202
- /// Jump to the target if the condition has the expected value,
203
- /// otherwise panic with a message and a cleanup target.
263
+ /// Evaluates the operand, which must have type `bool`. If it is not equal to `expected`,
264
+ /// initiates a panic. Initiating a panic corresponds to a `Call` terminator with some
265
+ /// unspecified constant as the function to call, all the operands stored in the `AssertMessage`
266
+ /// as parameters, and `None` for the destination. Keep in mind that the `cleanup` path is not
267
+ /// necessarily executed even in the case of a panic, for example in `-C panic=abort`. If the
268
+ /// assertion does not fail, execution continues at the specified basic block.
204
269
Assert {
205
270
cond : Operand < ' tcx > ,
206
271
expected : bool ,
@@ -209,7 +274,18 @@ pub enum TerminatorKind<'tcx> {
209
274
cleanup : Option < BasicBlock > ,
210
275
} ,
211
276
212
- /// A suspend point.
277
+ /// Marks a suspend point.
278
+ ///
279
+ /// Like `Return` terminators in generator bodies, this computes `value` and then a
280
+ /// `GeneratorState::Yielded(value)` as if by `Aggregate` rvalue. That value is then assigned to
281
+ /// the return place of the function calling this one, and execution continues in the calling
282
+ /// function. When next invoked with the same first argument, execution of this function
283
+ /// continues at the `resume` basic block, with the second argument written to the `resume_arg`
284
+ /// place. If the generator is dropped before then, the `drop` basic block is invoked.
285
+ ///
286
+ /// Not permitted in bodies that are not generator bodies, or after generator lowering.
287
+ ///
288
+ /// **Needs clarification**: What about the evaluation order of the `resume_arg` and `value`?
213
289
Yield {
214
290
/// The value to return.
215
291
value : Operand < ' tcx > ,
@@ -221,21 +297,39 @@ pub enum TerminatorKind<'tcx> {
221
297
drop : Option < BasicBlock > ,
222
298
} ,
223
299
224
- /// Indicates the end of the dropping of a generator.
300
+ /// Indicates the end of dropping a generator.
301
+ ///
302
+ /// Semantically just a `return` (from the generators drop glue). Only permitted in the same situations
303
+ /// as `yield`.
304
+ ///
305
+ /// **Needs clarification**: Is that even correct? The generator drop code is always confusing
306
+ /// to me, because it's not even really in the current body.
307
+ ///
308
+ /// **Needs clarification**: Are there type system constraints on these terminators? Should
309
+ /// there be a "block type" like `cleanup` blocks for them?
225
310
GeneratorDrop ,
226
311
227
- /// A block where control flow only ever takes one real path, but borrowck
228
- /// needs to be more conservative.
312
+ /// A block where control flow only ever takes one real path, but borrowck needs to be more
313
+ /// conservative.
314
+ ///
315
+ /// At runtime this is semantically just a goto.
316
+ ///
317
+ /// Disallowed after drop elaboration.
229
318
FalseEdge {
230
319
/// The target normal control flow will take.
231
320
real_target : BasicBlock ,
232
321
/// A block control flow could conceptually jump to, but won't in
233
322
/// practice.
234
323
imaginary_target : BasicBlock ,
235
324
} ,
236
- /// A terminator for blocks that only take one path in reality, but where we
237
- /// reserve the right to unwind in borrowck, even if it won't happen in practice.
238
- /// This can arise in infinite loops with no function calls for example.
325
+
326
+ /// A terminator for blocks that only take one path in reality, but where we reserve the right
327
+ /// to unwind in borrowck, even if it won't happen in practice. This can arise in infinite loops
328
+ /// with no function calls for example.
329
+ ///
330
+ /// At runtime this is semantically just a goto.
331
+ ///
332
+ /// Disallowed after drop elaboration.
239
333
FalseUnwind {
240
334
/// The target normal control flow will take.
241
335
real_target : BasicBlock ,
0 commit comments