@@ -151,7 +151,7 @@ called non-POFs.
151
151
152
152
Note that a non-POF may _ become_ a POF, for instance if all ` Drop ` objects are
153
153
moved out of scope, or if its only ` catch_unwind ` call is in a code path that
154
- will not be executed.
154
+ will not be executed. The next section provides an example.
155
155
156
156
[ cpp-POD-definition ] : https://en.cppreference.com/w/cpp/named_req/PODType
157
157
@@ -175,10 +175,36 @@ This RFC specifies that, regardless of the platform or the ABI string (`"C"` or
175
175
* _ undefined behavior_ if they cross non-[ POFs] [ POF-definition ]
176
176
* _ defined behavior_ when all unwound frames are POFs
177
177
178
- As an example, this means that Rust code can (indirectly, via C) invoke
179
- ` longjmp ` using the "C" ABI, and that ` longjmp ` can unwind or otherwise cross
180
- Rust [ POFs] [ POF-definition ] . If those Rust frames are not POFs, then invoking
181
- ` longjmp ` would be undefined behavior (and hence a bug).
178
+ As an example:
179
+
180
+ ``` rust
181
+ fn foo <D : Drop >(c : bool , d : D ) {
182
+ if c {
183
+ drop (d );
184
+ }
185
+ longjmp_if_true (c );
186
+ }
187
+
188
+ /// Calls `longjmp` if `c` is true; otherwise returns normally.
189
+ extern " C" fn longjmp_if_true (c : bool );
190
+ ```
191
+
192
+ If a ` longjmp ` occurs, it can safely traverse the ` foo ` frame, which will be a
193
+ POF because ` d ` has already been dropped.
194
+
195
+ Since ` longjmp_if_true ` function is using the ` "C" ` rather than the `"C
196
+ unwind"` ABI, the optimizer may assume that it cannot unwind; on LLVM, this is
197
+ represented by the ` nounwind ` attribute. On most platforms, ` longjmp ` is not a
198
+ form of unwinding: the ` foo ` frame is simply discarded. On Windows, ` longjmp `
199
+ is implemented as a forced unwind, which is permitted to traverse ` nounwind `
200
+ frames. Since ` foo ` contains a ` Drop ` type the forced unwind will include a
201
+ call to the frame's cleanup logic, but that logic will not produce any
202
+ observable effect; in particular, ` D::drop() ` will not be called again. The
203
+ observable behavior should therefore be the same on all platforms.
204
+
205
+ Conversely, if, due to a bug, ` longjmp ` were called unconditionally, then this
206
+ code would have undefined behavior on all platforms when ` c ` is false, because
207
+ ` foo ` would not be a POF.
182
208
183
209
[ inside-rust-forced ] : https://blog.rust-lang.org/inside-rust/2020/02/27/ffi-unwind-design-meeting.html#forced-unwinding
184
210
0 commit comments