Skip to content
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

[expr.sizeof] Clarify padding in class types CWG2609 #5560

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

jensmaurer
Copy link
Member

@jensmaurer jensmaurer commented Jul 11, 2022

@JohelEGP
Copy link
Contributor

This originated from cplusplus/CWG#89, right?

@jensmaurer
Copy link
Member Author

Right.

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 12, 2022

Doesn't this clarification negative the consensus in cplusplus/CWG#89 (comment)

I think what we have here is neither. It's not implementation-defined (no documentation requirement) and it's not unspecified (we shouldn't pretend it might vary from evaluation to evaluation). It's "implementation-defined without documentation requirement", it seems.

@jensmaurer
Copy link
Member Author

No. We don't say here that sizeof(S) (the expression) is unspecified, which would lead to the interpretation that every evaluation can yield a different value. Instead, we say the size of a class type is unspecified. Since there is only one definition of a class type in the entire program [basic.def.odr], it follows that there can be only one (fixed) size for a program (run). Which is what we want.

@frederick-vs-ja
Copy link
Contributor

#5087 suggested that "The representation of a fundamental type is unspecified except as stated in this subclause.". Is such change still suitable?

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 12, 2022

Instead, we say the size of a class type is unspecified.

The result of sizeof(S) where S is a class type is defined as

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

Isn't that just saying the result is the size of the class type? I don't understand what's the difference here. Moreover, the result of sizeof(S) depends on the required padding, since we say

The amount and placement of padding in a class type is unspecified.

Isn't that exactly implying that the result of sizeof(S) is unspecified since the required padding(if any)?

Anyway, [basic.def.odr](especially p14) didn't impose any requirement on the size of a class.

@jensmaurer
Copy link
Member Author

[basic.def.odr] says all class types with a given name are the same throughout the program.

Note that sizeof(S) is an expression that might be evaluated multiple times and might yield different results for each evaluation if we say "unspecified result" for that. If we instead say that the size of the class is unspecified, it seems to convey the meaning better that the size stays constant throughout the program run.

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 12, 2022

[basic.def.odr] says all class types with a given name are the same throughout the program.

Generally speaking, [basic.def.odr] essentially requires these user-declared declarations shall obey some rules(such as they have the same tokens) such that they have a consistent definition as if they are a single definition. However, as the padding bits, are not controlled by users. Instead, they are implied processed by the implementations according to the relevant circumstances. Either from this perspective or from the normative definitions in [basic.def.odr], they all impose no requirement that all definitions of the same class should have a consistent size unless we can point out the rule.

it seems to convey the meaning better that the size stays constant throughout the program run

Why not squarely say

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array, which is implementation-defined; no documentation is required.

Honestly, I don't see, if we say

the size of the class is unspecified

why is the result of sizeof(Class), which strongly depends on the size of the class, instead not unspecified? Doesn't "the size of the class" means how many bytes an object of that class would occupy?

@frederick-vs-ja
Copy link
Contributor

Either from this perspective or from the normative definitions in [basic.def.odr], they all impose no requirement that all definitions of the same class should have a consistent size unless we can point out the rule.

I think they do strongly imply that the same class should have a consistent size. Otherwise, it's even not guaranteed that variable definition like inline Foo<sizeof(T)> x; can obey ODR. But it's not clear to me whether there's such a strict requirement.

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 13, 2022

I think they do strongly imply that the same class should have a consistent size.

AFAIK, the touched rules for your case inline Foo<sizeof(T)> x; are [temp.over.link], [basic.def.odr] p14. The former actually quotes the latter. [basic.def.odr] p14 essentially requires all tokens that form these definitions should be the same, which is regardless of size. Also, [basic.def.odr] p14 also requires that the lookup for a name shall refer to the same entity, this is basically regulated by [basic.scope.scope] and [basic.link], in short, these declarations found for the name should correspond and they obey [basic.link], which is regardless of size too. The other bullets in [basic.def.odr] p14 also impose no requirement on the size of the entity.

But it's not clear to me whether there's such a strict requirement.

So, in order to ensure that each evaluation of sizeof(T) results in a consistent value, we should explicitly specify it through some other rules instead of relying on the [basic.def.odr] that is hazy/specious for this part.

@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented Jul 13, 2022

Also, [basic.def.odr] p14 also requires that the lookup for a name shall refer to the same entity, this is basically regulated by [basic.scope.scope] and [basic.link], in short, these declarations found for the name should correspond and they obey [basic.link], which is regardless of size too.

Foo<sizeof(T)> may refer to different entities if sizeof(T) varies.

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 13, 2022

Foo<sizeof(T)> may refer to different entities if sizeof(T) varies.

[temp.over.link] didn't mention the result of an expression at all, it just says

Two expressions involving template parameters are considered equivalent if two function definitions containing the expressions would satisfy the one-definition rule, except that the tokens used to name the template parameters may differ as long as a token used to name a template parameter in one expression is replaced by another token that names the same template parameter in the other expression.

Foo<sizeof(T)> and Foo<sizeof(U)> are equivalent if T and U are used to name the same template parameter.

@jensmaurer
Copy link
Member Author

Obviously, we can only meaningfully talk about the possibly unspecified runtime result of sizeof after template instantiation. I have understood Foo<sizeof(T)> to mean "any type T that you care to name here", not a reference to a template parameter.

Nobody should be talking about templates here.

@frederick-vs-ja
Copy link
Contributor

Nobody should be talking about templates here.

Perhaps my fault. I meant that T is some certain class type.

I should use the aforementioned certain type S and inline char x[sizeof(S)]; in the example, and refer to [basic.link]/(11.1) instead...

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 13, 2022

AFAIK, we can only check whether stuff satisfies a particular rule or not rather than that in order to satisfy the rule the stuff must be what it might not be.

char x[size];

The rule says size must be a constant expression, we just need to check whether size violates the rule or not. Instead of assuming that size was a constant expression since it appears in a context that requires it to be a constant expression.

The truth should be that since some rules explicitly say the result of sizeof(S) is consistent in a program, all arrays declared with sizeof(S) elements have the same number of elements. The logic in the above comments seems to say in order to make these arrays that are declared with sizeof(S) have the same number of elements, sizeof(S) should always be the same, which is no justification.

In other words, we can infer the result from conditions but we cannot infer conditions from a result. The result is 5, so I say the condition must be 1+4, really?

@frederick-vs-ja
Copy link
Contributor

The truth should be that since some rules explicitly say the result of sizeof(S) is consistent in a program, all arrays declared with sizeof(S) elements have the same number of elements. The logic in the above comments seems to say in order to make these arrays that are declared with sizeof(S) have the same number of elements, sizeof(S) should always be the same, which is no justification.

No. I only meant the single array x and multiple declarations/definitions of x, not "these arrays". I believe that in order to guarantee that a program containing such declarations well-formed, sizeof(S) cannot vary between instances.

If a strict requirement is actually missing, both "a program containing such declarations is well-formed" and "sizeof(S) doesn't vary between instances" fall back to "should".

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 13, 2022

I believe that in order to guarantee that a program containing such declarations well-formed, sizeof(S) cannot vary between instances.

Don't you try to infer the conditions from the result? You mean, in order to get that result, you predict the condition must be true.

The truth should be

Since some rules say sizeof(S) cannot vary between instances, thus a program containing such declarations is guaranteed to be well-formed.

For example:

float f = 256.0f;
char c = f;

You shouldn't infer that the program is well-formed just because each run of this program would always get a constant value for c(the observable result is always 0).

The justified process is that, given a set of conditions, if all conditions in the set do not violate any rule defined in this document, then the program is well-formed. Instead of saying that since the program always has a consistent observable result, thus all conditions that form that program are all defined.

@frederick-vs-ja
Copy link
Contributor

Don't you try to infer the conditions from the result? You mean, in order to get that result, you predict the condition must be true.

My oversight. I meant to say the value should not vary among all of the aforementioned instances (that determine the type of x), which implies that there are some circumstances in which sizeof(S) should not change.
(Perhaps it's not good to continue talking about ∃ and ∀ here...)

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 14, 2022

which implies that there are some circumstances in which sizeof(S) should not change.

This should have at least an explicit rule to say the result of sizeof applied to a class type is not unspecified. Anyway, in the current modification, the wording says

The amount and placement of padding in a class type is unspecified.

Isn't it together with [expr.sizeof] p2

When applied to a class, the result is the number of bytes in an object of that class including any padding required for placing objects of that type in an array.

, [basic.types.general] p4

Bits in the object representation that are not part of the value representation are padding bits.

, and [intro.memory] p1

A byte is ... and is composed of a contiguous sequence of bits

can conclude that the bytes in an object of class type are unspecified? Again, how many bytes depend on how many bits there are, the number of the bits is unspecified since the number of padding bits is unspecified, so the number of the former is as well. Their relationships can be deducible in mathematics.

@jensmaurer jensmaurer changed the title [expr.sizeof] Clarify padding in class types [expr.sizeof] Clarify padding in class types CWG2609 Jul 15, 2022
@jensmaurer jensmaurer added cwg Issue must be reviewed by CWG. not-editorial Issue is not deemed editorial; the editorial issue is kept open for tracking. labels Jul 15, 2022
@jensmaurer
Copy link
Member Author

Handled by CWG2609

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cwg Issue must be reviewed by CWG. not-editorial Issue is not deemed editorial; the editorial issue is kept open for tracking.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

CWG2609 [expr.sizeof] The result of applying sizeof to empty class is standard?
4 participants