replace shadowed return token by unsafe-to-create token#117
Open
BennoLossin wants to merge 1 commit intomainfrom
Open
replace shadowed return token by unsafe-to-create token#117BennoLossin wants to merge 1 commit intomainfrom
unsafe-to-create token#117BennoLossin wants to merge 1 commit intomainfrom
Conversation
|
This email is fine 👍 |
Member
Author
|
Perfect. Thanks a lot for catching this issue! |
nbdd0121
reviewed
Mar 9, 2026
nbdd0121
reviewed
Mar 9, 2026
40bc552 to
e981f14
Compare
We use a unit struct `__InitOk` in the closure generated by the
initializer macros as the return value. We shadow it by creating a
struct with the same name again inside of the closure, preventing early
returns of `Ok` in the initializer (before all fields have been
initialized).
In the face of Type Alias Impl Trait (TAIT) and the next trait solver,
this solution no longer works [1]. The shadowed struct can be named
through type inference. In addition, there is an RFC proposing to add
the feature of path inference to Rust, which would similarly allow [2]
Thus remove the shadowed token and replace it with an `unsafe` to create
token.
The reason we initially used the shadowing solution was because an
alternative solution used a builder pattern. Gary writes [3]:
In the early builder-pattern based InitOk, having a single InitOk
type for token is unsound because one can launder an InitOk token
used for one place to another initializer. I used a branded lifetime
solution, and then you figured out that using a shadowed type would
work better because nobody could construct it at all.
The laundering issue does not apply to the approach we ended up with
today.
With this change, the example by Tim Chirananthavat in [1] no longer
compiles and results in this error:
error: cannot construct `pin_init::__internal::InitOk` with struct literal syntax due to private fields
--> src/main.rs:26:17
|
26 | InferredType {}
| ^^^^^^^^^^^^
|
= note: private field `0` that was not provided
help: you might have meant to use the `new` associated function
|
26 - InferredType {}
26 + InferredType::new()
|
Applying the suggestion of using the `::new()` function, results in
another expected error:
error[E0133]: call to unsafe function `pin_init::__internal::InitOk::new` is unsafe and requires unsafe block
--> src/main.rs:26:17
|
26 | InferredType::new()
| ^^^^^^^^^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
Reported-by: Tim Chirananthavat <theemathas@gmail.com>
Link: rust-lang/rust#153535 [1]
Link: rust-lang/rfcs#3444 (comment) [2]
Link: rust-lang/rust#153535 (comment) [3]
Signed-off-by: Benno Lossin <lossin@kernel.org>
e981f14 to
9a052c3
Compare
56 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
@theemathas let me know if you're okay with me listing you as the
Reported-by(or if I should use a different email).I wanted to include your example from the issue to ensure that we don't forget about this in the future, but I will have to add a way to run ui tests with compiler flags, as
trybuilddoesn't natively support that.We use a unit struct
__InitOkin the closure generated by the initializer macros as the return value. We shadow it by creating a struct with the same name again inside of the closure, preventing early returns ofOkin the initializer (before all fields have been initialized).In the face of Type Alias Impl Trait (TAIT) and the next trait solver, this solution no longer works [1]. The shadowed struct can be named through type inference. In addition, there is an RFC proposing to add the feature of path inference to Rust, which would similarly allow [2]
Thus remove the shadowed token and replace it with an
unsafeto create token.The reason we initially used the shadowing solution was because an alternative solution used a builder pattern. Gary writes [3]:
The laundering issue does not apply to the approach we ended up with today.
With this change, the example by Tim Chirananthavat in [1] no longer compiles and results in this error:
Applying the suggestion of using the
::new()function, results in another expected error:Reported-by: Tim Chirananthavat theemathas@gmail.com
Link: rust-lang/rust#153535 [1]
Link: rust-lang/rfcs#3444 (comment) [2]
Link: rust-lang/rust#153535 (comment) [3]