-
Notifications
You must be signed in to change notification settings - Fork 488
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[type-layout] Document minimum size and alignment #1482
Conversation
src/type-layout.md
Outdated
- For a [trait object](#trait-object-layout), the minimum size is 0 and the minimum | ||
alignment is 1 | ||
- For a struct type with a dynamically-sized field, the minimum size is taken to be | ||
the size of the struct when the dynamically-sized field has *its* minimum size. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alignment affects size, so discussing the two separately here doesn't quite work.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you suggesting just adjusting it to say this?
For a struct type with a dynamically-sized field, the minimum size is taken to be the size of the struct when the dynamically-sized field has its minimum size and alignment.
(Done. I can revert if I misunderstood your suggestion.)
src/type-layout.md
Outdated
this property provides *no* guarantees about [`repr(Rust)`](#the-rust-representation) | ||
types, as such a type can have arbitrarily large size and alignment regardless of | ||
the sizes and alignments of its fields | ||
- Every type's minimum size is less than or equal to `isize::MAX` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bullet doesn't belong into the list of "notable cases of minimum size and alignment are", it belongs before or after the list. Also it should say what happens when one declares a type whose minimum size exceeds this limit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This bullet doesn't belong into the list of "notable cases of minimum size and alignment are", it belongs before or after the list.
Done.
Also it should say what happens when one declares a type whose minimum size exceeds this limit.
Do we need to specify that? Presumably the implication is just that such a program would not conform to the spec, and so we couldn't permit it to compile, but a) that's a logical implication of the text here and, b) I don't believe we need to specify the manner in which it fails to compile.
I'm happy to also specify that such programs won't compile - I just want to make sure I'm understanding correctly that this is just a nice-to-have rather than something that affects the semantics of this text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to specify that?
I think so, yes. If we leave it implicit it could understood to be anything from UB to a compile-time error. (We don't do "UB by omission" in Rust but people might think we do. And some sort of run-time panic does seem like a not unreasonable interpretation to me.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable. Presumably resolving #1482 (comment) is required in order for us to agree on a wording for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The questions of "which types are checked" and "what happens when a type fails the check" seem orthogonal to me, so I don't see an overlap with the other discussion.
There's a potential issue here -- not all types mentioned in the source code actually make it to codegen, so sometimes types that are "too big" do not lead to errors. This example fails to build in a debug build but succeeds as a release build: #![crate_type = "lib"]
pub fn f() {
g::<u16>();
}
pub fn g<T>() -> std::mem::MaybeUninit<[T; 1 << 47]> {
std::mem::MaybeUninit::uninit()
} |
Good call. This shouldn't be a problem in our motivating use case, but obviously we need to be careful with what we promise. Intuitively, the guarantee is something like "a type which you can do anything with" or "a type which you can create a pointer to". But I'm not sure how to formalize that idea. For the motivating use case, we need to guarantee that this holds of |
The new wording sounds good to me. However, the issue with "which types actually end up being size-checked" remains. I don't have a good idea for how to express that. @rust-lang/opsem @rust-lang/lang: any thoughts? There's tow questions; the easy one is what you think about the text of the PR, but the harder one is this concern. Specifically, the question is for which types we guarantee that their size is less than I don't have a good idea for how to even say which types are guaranteed to be size-checked in the current implementation. Similar to what we did for const-eval failures, we could try to have a notion of "required types" such that if a function runs, these types are definitely size-checked -- but given the huge number of types in a typical program, that sounds like it could be quite expensive. |
Is there some notion of "observability" we could use here? As in, if a type's existence is "observable" in some way? Intuitively, I'd imagine this just means that if the execution of a program in any way depends on the existence of the type (calling |
The only things that are "observable" about a program are its IO behavior (and volatile accesses). That's the usual as-if rule. So I don't think that will help us here. |
- For a [trait object](#trait-object-layout), the minimum size is 0 and the minimum | ||
alignment is 1 | ||
- For a struct type with a dynamically-sized field, the minimum size is taken to be | ||
the size of the struct when the dynamically-sized field has *its* minimum size and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not clear on what "it" refers to in this sentence
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the answer is value-dependent, e.g., for Foo<dyn Blah>
the alignment depends on the value stored in the vtable -- put another way, it's determined by the "erased information"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You mean "its"? It is straight-forward recursion. If a struct has field types T, U, V
where V
is dyn-sized, then the min size of the struct is computed using the min size and min align of V
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That formulation seems much clearer :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Though I still am not clear on what "the min align of V
" is in the context I mentioned i.e., I would appreciate a note on whether it is value-dependent (I believe so)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The minimum alignment is not value-dependent, no. Minimum size and minimum alignment are static properties that every type possesses.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see.
FWIW after further discussion, my conclusion is that all we really need for @joshlf's usecase right now is rust-lang/rust#126152. That avoids having to document when exactly compilation fails due to types being bigger than IOW, the entire point of this PR is to be able to say "Every type's minimum size is less than or equal to |
@rustbot labels -I-lang-nominated OK. Per RalfJ's comment then, let's close in favor of rust-lang/rust#126152. If further discussion manages to work out some solution to the problems that RalfJ mentioned, feel free to reopen. |
This is a draft implementation of rust-lang/rust#117474 (comment). I'm happy to make any suggested edits.
cc @RalfJung