@@ -105,13 +105,34 @@ impl<'a> Iterator for SwitchTargetsIter<'a> {
105105
106106impl < ' a > ExactSizeIterator for SwitchTargetsIter < ' a > { }
107107
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.
108123#[ derive( Clone , TyEncodable , TyDecodable , Hash , HashStable , PartialEq ) ]
109124pub enum TerminatorKind < ' tcx > {
110- /// Block should have one successor in the graph ; we jump there.
125+ /// Block has one successor; we continue execution there.
111126 Goto { target : BasicBlock } ,
112127
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.
115136 SwitchInt {
116137 /// The discriminant value being tested.
117138 discr : Operand < ' tcx > ,
@@ -124,29 +145,62 @@ pub enum TerminatorKind<'tcx> {
124145 targets : SwitchTargets ,
125146 } ,
126147
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.
129154 Resume ,
130155
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.
133160 Abort ,
134161
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.
138173 Return ,
139174
140175 /// Indicates a terminator that can never be reached.
176+ ///
177+ /// Executing this terminator is UB.
141178 Unreachable ,
142179
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.
144196 Drop { place : Place < ' tcx > , target : BasicBlock , unwind : Option < BasicBlock > } ,
145197
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:
150204 ///
151205 /// ```
152206 /// BB0 {
@@ -170,15 +224,22 @@ pub enum TerminatorKind<'tcx> {
170224 /// }
171225 /// ```
172226 ///
173- /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass .
227+ /// Disallowed after drop elaboration .
174228 DropAndReplace {
175229 place : Place < ' tcx > ,
176230 value : Operand < ' tcx > ,
177231 target : BasicBlock ,
178232 unwind : Option < BasicBlock > ,
179233 } ,
180234
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
182243 Call {
183244 /// The function that’s being called.
184245 func : Operand < ' tcx > ,
@@ -187,7 +248,7 @@ pub enum TerminatorKind<'tcx> {
187248 /// This allows the memory occupied by "by-value" arguments to be
188249 /// reused across function calls without duplicating the contents.
189250 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 .
191252 destination : Option < ( Place < ' tcx > , BasicBlock ) > ,
192253 /// Cleanups to be done if the call unwinds.
193254 cleanup : Option < BasicBlock > ,
@@ -199,8 +260,12 @@ pub enum TerminatorKind<'tcx> {
199260 fn_span : Span ,
200261 } ,
201262
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.
204269 Assert {
205270 cond : Operand < ' tcx > ,
206271 expected : bool ,
@@ -209,7 +274,18 @@ pub enum TerminatorKind<'tcx> {
209274 cleanup : Option < BasicBlock > ,
210275 } ,
211276
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`?
213289 Yield {
214290 /// The value to return.
215291 value : Operand < ' tcx > ,
@@ -221,21 +297,39 @@ pub enum TerminatorKind<'tcx> {
221297 drop : Option < BasicBlock > ,
222298 } ,
223299
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?
225310 GeneratorDrop ,
226311
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.
229318 FalseEdge {
230319 /// The target normal control flow will take.
231320 real_target : BasicBlock ,
232321 /// A block control flow could conceptually jump to, but won't in
233322 /// practice.
234323 imaginary_target : BasicBlock ,
235324 } ,
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.
239333 FalseUnwind {
240334 /// The target normal control flow will take.
241335 real_target : BasicBlock ,
0 commit comments