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

[intro.object] Does the attributive clause intend to be a constraint or to convey a result? #5630

Open
xmh0511 opened this issue Jul 20, 2022 · 45 comments

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Jul 20, 2022

These operations select one of the implicitly-created objects whose address is the address of the start of the region of storage, and produce a pointer value that points to that object, if that value would result in the program having defined behavior.

The attributive clause in this sentence makes the rule read like that: only the address of the object is the address of the start of the region will it be possible to be selected as a suitable created object. However, as discussed in cplusplus/CWG#98, the intent should be read as that: a suitable created object that would make the program well-formed will have the address of the start of the region.

I think they are completely different meanings. If the intent is the latter, the following change will make the meaning clear

These operations select one of the implicitly-created objects as the suitable created object, and produce a pointer value that points to that object, if that value would result in the program having defined behavior; the address of such a suitable created object is the address of the start of the region of storage.

@frederick-vs-ja
Copy link
Contributor

You said that:

Back to [intro.object], it says that an object whose address is YYY is considered as a suitable created object if Condition is true. It didn't say an object that can be considered a suitable created object will have its address be YYY if Condition is true.

They are completely different meanings.

But I don't think they are essentially different meanings in the C++ standard, because the divergence is only present in undefined behavior, for which the standard doesn't impose any different requirement ([intro.compliance.general]/1, /2). I don't think it's reasonable to imply something like that "there may be a suitable created object whose address is not the address of the start of the region, but its address is selected only on UB". As such an object is hardly to be said "suitable".

(And there's no such a selection that would make the program ill-formed. Perhaps you intended to say "well-defined".)

It seems that the item "suitable created object" is not clearly defined, and it's reasonable to me to restrict every possible suitable created object to have the same address as the start of the storage within which it is implicitly created.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Jul 21, 2022

It seems that the item "suitable created object" is not clearly defined

A suitable created object is one of the implicitly created objects that can result in a program well-defined. This is the intent of p0593. To say which implicitly created object can be as the suitable created object is induced by users, as long as providing that such a usage would be well-defined.

My complaint is, in the current wording(especially the attributive clause), that sounds like we should first filter these implicitly created objects to form a candidate set, (again, the attributive clause implies)that only the address of the implicitly created object is the address of the start of the region will it be eligible to be the element in the candidate set. The suitable created object must arise from the candidate set.

This is a bit strange, these operations didn't say which implicitly created objects they created would have their addresses be the start of the region.

Through reading P0593, it's simple that its intent is, that the address of the object is the address of the start of the region if the object is a suitable created object.


it's reasonable to me to restrict every possible suitable created object to have the same address as the start of the storage within which it is implicitly created.

That's what I've been trying to say. I want to correctly express this meaning through the proposed wording. it appears to me all implicitly created objects are possible to be the suitable created object, and a suitable created object is one of the implicitly created objects, and using a pointer value that points to such an object would make a program well-defined, such an object is a so-called suitable created object, and therefore the address of such an object is the address of the start of the region.

I think an object's address is the address of the start of the region should be considered as the result that the object is a suitable created object, instead of being a condition that the object can be a suitable created object. The attributive clause does reflect the latter.

@jensmaurer
Copy link
Member

jensmaurer commented Mar 9, 2023

Looking at the original description in this issue, "whose" is restrictive here (and intended to be so): We take a set (in this case, implicitly created objects in some region of storage) and filter that set for elements with a given property. Then we select a single element from the filtered set.

Case 1: The user wants to use an object of type T at the start of the storage. This just works; we've selected the object of type T among the implicitly created objects located at the start of the memory.

Case 2: The user wants to use an object of type T somewhere in the middle of the storage. Thus, there is some unused space at the beginning of the storage. This works; we've selected the implicitly created object of type "unsigned char" located at the start of the memory and returned a pointer to it. There is also an implicitly created object of type T in the middle of the storage that can be used. Together, the program has defined behavior in that situation, and we're fine.

If you believe these cases don't cover everything, please post a specific code example that you believe doesn't work as it should under the rules.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 10, 2023

With the opinions "case 1" and "case 2", consider this example:

struct A{
    int a, b;
};
A* ptr = (A*)malloc(sizeof(A)* sizeof(char) * 10);  
ptr->a = 0;  // well-defined?
ptr->b = 1;  // well-defined?

Is this example well-defined? I say it's undefined because I want to use an object of type A somewhere in the middle of the storage, as said in case 2. Obviously, the address returned by malloc should be the start of the region, which is not the address where my expected object locates, indirection of a pointer that does not point to the object of type A is UB because the pointer points to the element of "unsigned char". Another person says it's well-defined because he wants to use an object of type A at the start of the storage, as said in case 1. So, the question is what hell whether the example is well-defined or not. According to the reading of "case 1" and "case 2", whether the example is well-defined is determined by how you think, rather than how the program could be. This results in different people having different outcomes.

The first person thinks the created object locates the address offsetting sizeof(A) from the start of the region, the second person thinks that address offsetting 2x sizeof(A) from the start of the region, and so forth.

So, what I want to convey here is, any suitable implicitly created object could locate the address of the start of the region, instead of saying the suitable object candidates are formed from these objects whose address is the start of the region.

It is the question that the "address of the start of the region" is the result or the cause.


Looking at the original description in this issue, "whose" is restrictive here (and intended to be so): We take a set (in this case, implicitly created objects in some region of storage) and filter that set for elements with a given property. Then we select a single element from the filtered set.

Since it is restrictive, we should know which objects satisfy the restriction, that is, we should define which object has the property. For example:

{ x | x > 0}, x ∈ R

When we try to form the set, we should first define which numbers are in R and which numbers are defined as greater than 0. Analogy:

{ object | object whose address is the start of the region }, object ∈ implicitly creating objects

@jensmaurer
Copy link
Member

jensmaurer commented Mar 10, 2023

I say it's undefined because I want to use an object of type A somewhere in the middle of the storage, as said in case 2.

Not really. The code shown uses an "A" at the start of the storage (and then, there's some unused storage after "A"), because the value returned by malloc is the address of the start of the storage (regardless of the pointer value, which is more than the address).

The "address of the start of the storage" is a parameter to the selection of one of the implicitly created objects, not an outcome of that selection.

Which objects are in the base set? All possible objects of any of the implicit-lifetime types.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 10, 2023

The "address of the start of the storage" is a parameter to the selection of one of the implicitly created objects, not an outcome of that selection.

Look at this Set:

{ object | object whose address is the start of the region }, object ∈ implicitly creating objects

We do define what is "implicitly creating objects", so we clearly know which objects are/could be implicitly creating objects, however, "object whose address is the start of the region" where each object is selected from the set of implicitly creating objects to form a smaller set comprising suitable created objects, the filtering condition is the object should have its address the start of the region, this requires us to know which object whose address is the start of the region, so, which rule in the standard clarifies this point?


Which objects are in the base set? All possible objects of any of the implicit-lifetime types.

All possible objects of any of the implicit-lifetime types form the implicitly creating objects, called S1. The suitable created objects again are selected from S1, the condition of the selection is that the object's address is the start of the region.

So, which objects whose address is the start of the region? Which is the condition for the selection of suitable created objects.


I use a simple example to expose the issue.

In the classroom(there are girls and boys), the students who are boys form the group A, then, the student in group A whose age is greater than 10 form the suitable work group B.

Each time we select students to form a group, we do have a condition. Before forming group A, we should know which students are boys, before forming group B, we should know which students in group A whose age is greater than 10. Similar for forming the set of suitable created objects, first we select objects to form the set of implicitly creating objects(set A), the condition is the types of the objects are implicit-lifetime type, then we selected objects in set A to form the set of suitable created objects, the condition is these objects' address are the start of the region.

@jensmaurer
Copy link
Member

We are not choosing a single male student with age > 10, we choose all of these. And then, we let them live a little, and then we determine which one has been the quietest (= gives the rest of the program defined behavior), and that's the one we retroactively choose.

Or is the problem that the "start of the region" is underspecified?
I think the C wording is not stellar in this regard, but it's pretty obvious that malloc(n) returns a region of storage of size n, and that region has a start and the start has an address (prior to any implicit lifetime considerations coming into play).

Or is the problem that the address of an object is underspecified? I don't think so.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

And then, we let them live a little, and then we determine which one has been the quietest

"quietest", for example, means do not make noise, then we will observe every student to check whether he satisfies "quietest", all students satisfying this selection criterion form the eventual candidates. When we say to select something x whose property is y, we should first know what properties x has, then we check whether the property of x is y or not. As the "quietest", we first need to know which students make noise and which do not, these students who do not make noise satisfy the "quietest".

Similarly, we will check whether these objects satisfy "whose address is the start of the region", these objects that satisfy this selection criterion form the suitable implicitly created objects.

So, how to judge whether an object satisfies "whose address is the start of the region" or not? If we do not specify which objects can have their address at the start of the region, how do we know which object whose address is the start of the region? So, the concern is

which objects in the region created by malloc could have their address at the start of the region, which is underspecified.

In general, we lack a judgment basis. The expected supplementary rule is:

We may specify any complete object could/is able to have its address at the start of the region.

Such as the above example struct A{int a, int b};, the complete object A can have its address at the start of the region, but the subobject b cannot, for subobject a, it is ruled by pointer-interconvertible. That is, the pointer produced by malloc cannot point to the subobject b but it can point to the complete object of class A or indirect to subobject a. With this specification, we will have the judgment basis to determine which object is reasonable to be "whose address is the start of the region".


If still don't understand what I meant, give this example:

for A, B, C, D, ... candidates, we will hire people who have worked in C++ for more than 20 years.

In order to select out of these people, we should first know how long they work in C++, aren't we? If we didn't supply the information(how long they work in C++) of the people on the list, how do we complete the selection/filtering?

@jensmaurer
Copy link
Member

We're not making much progress here.

It seems you're saying that either "address of an object" is underspecified, or "(address of) the start of the region returned by the malloc function" is underspecified. Which is it? Both are unrelated to and are determined independent of any implicit object creation.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

It seems you're saying that either "address of an object" is underspecified, or "(address of) the start of the region returned by the malloc function" is underspecified. Which is it?

Compare to the second opinion, I would choose that: "address of an object" is underspecified. At least, in this context, we don't specify which objects in the set of implicitly creating objects we are considering are able to be considered to have the address that is the start of the allocated region, which can let us know which objects are eligible to be implicitly-created objects whose address is the address of the start of the region of storage.


Simply speaking, as @frederick-vs-ja said:

It seems that the item "suitable created object" is not clearly defined ...

Since the operation always returns the pointer value that points to one of "suitable created objects". In this perspective, we should define which implicitly created objects can be "suitable created objects". Then we just need to say

These operations select one of the implicitly-created objects whose address is the address of the start of the region of storage suitable created objects, and produce a pointer value that points to that object.

Without needing to concern about the detail of addresses.

@jensmaurer
Copy link
Member

What we're trying to define here is "suitable created object" (note the italics in the preceding sentence), so shuffling the words around doesn't help.

Ok, so the question is "what is the address of an object".

[intro.object] p9 says "Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies."
and "The address of a non-bit-field subobject of zero size is the address of an unspecified byte of storage occupied by the complete object of that subobject."

Each object has an object representation, and we're talking about the storage taken up by that object representation.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

What we're trying to define here is "suitable created object"

So, the definition of "suitable created object" is an object that:

  1. is an implicitly created object, and
  2. whose address is the address of the start of the region allocated by malloc

For the first condition, we clearly know these objects that are of implicit-lifetime types are implicitly created objects. For the second condition, we cannot know which objects whose address is the address of the start of the region. [intro.object] merely says what "address" is and how an object can have the address. This sounds like people have their ages, age is how many years have gone counted from when the person was born, and age is an integer number. Now, there are A, B, C in the region, the person in the region whose age is 20 is a suitable candidate. Please tell me, who is the suitable candidate? I didn't say anything about how old every person is except that gives the definition of "age".


In addition, when we select/filter something in terms of certain property, we should exactly know what the value of the property is. For example:

a person whose age is 20 is a suitable candidate. In this case, we need to know the numbers of ages of every person in the set in order to determine the candidate.

a person whose home address is XXX, YYY, 1024 is a suitable candidate. In this case, we need to know the home addresses of every person in the set in order to determine the candidate.

an object whose address is the address of the start of the region is a suitable created object. In this case, we need to at least know which objects whose addresses are that address.

@jensmaurer
Copy link
Member

You seem to be saying that "the address of an object" is not sufficiently specified. Which, to my reading, means you believe that

struct A { int a; int b; } x;
A *p = &x;
A *q = &x;
bool b = p == q;  // not properly specified

because we have to determine "represents the same address" per expr.eq p3.2 to determine whether we get true or false, but we don't know whether a pointer pointing to an object "represents the address" of that object.

I don't quite follow that; we have "Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies." and [basic.compount] p3 "A value of a pointer type that is a pointer to or past the end of an object represents the address of the first
byte in memory (6.7.1) occupied by the object or the first byte in memory after the end of the storage occupied by the object, respectively."

For the example

struct B { int a; int b; } x;

we know that the address of x.a is different from the address of x.b because of [intro.object] p9 "they have distinct addresses", and [expr.rel] tells us that the address of x.a is actually smaller than the address of x.b. Thus, the address of x.b cannot be the same as the address of x, because we know that the address of x is "the address of the first byte it occupies".

There is a bit of implementation-dependence around the layout of classes, too, so not everything in that area is specified by the standard.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

I am not sure whether I have conveyed my thought clearly, but you haven't understood what I meant yet. Let us go back to your comment at #5630 (comment)

Looking at the original description in this issue, "whose" is restrictive here (and intended to be so): We take a set (in this case, implicitly created objects in some region of storage) and filter that set for elements with a given property. Then we select a single element from the filtered set.

The implicitly created objects form the base set, right? Then we filter the base set by applying the condition/property "whose address is the address of the start of the region" to form a set of suitable candidates, right? So, how do we check every object in the base set to see whether they have the property, or say, satisfy the condition? Or, given this example

struct B{};
struct A{
   int a;
   B b;
};
malloc(sizeof(A));

Before the malloc produces the pointer value to the suitable created object, please tell me which implicitly created objects can be assumed to have their first byte at the start of the region allocated by malloc, and which rule tells us that?


And back to your above comment, in the first case bool b = p == q;, we do not have to know the exact value of the address. Because they point to the same object, so they have the same address, as per [basic.compound] p4, as like, if x > 5, then x > 0 (x∈ Z) it always true, we do not need to know what exact number x denotes, we do not need to know whether x is 6, 7, 8, 9, or so on. However, if we say the number that is 0 is suitable XXX, we do need to know whether x is 0 or other values because we impose the exact restriction and use this restriction to filter set.

@jensmaurer
Copy link
Member

jensmaurer commented Mar 11, 2023

An object of an unspecified implicit-lifetime type whose size and alignment requirements are satisfied by the region of storage allocated by malloc.

So, at least an object of each of the types un/signed char, char, un/signed short, and un/signed int as well as of (complete) types A and B could be implicitly created at the start of the storage returned by malloc. The B subobject of A is implicitly created as part of possibly implicitly creating A, but that one is not at the same address as the containing A. However, the region of storage must contain the entire A object, thus the B subobject cannot be at the start of the region allocated by malloc.

[intro.object] p10

I don't follow your argument about "exact address"; all we need to know is that there is a region of storage, it has a start address, and we can place objects into that storage. Whether we do that implicitly or by (say) placement-new doesn't change much, I think.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

So, at least an object of each of the types un/signed char, char, un/signed short, and un/signed int as well as of (complete) types A and B could be implicitly created at the start of the storage return by malloc. The B subobject of A is implicitly created as part of possibly implicitly creating A, but that one is not at the same address as the containing A. However, the region of storage must contain the entire A object, thus the B subobject cannot be at the start of the region allocated by malloc.

The whole interpretation is what I am asking here. We lack the form rule that corresponds to the whole interpretation. The whole interpretation can be concise to a rule:

Any complete objects that are implicitly created objects can be assumed to have their address to be the address of the start of the region.

If a complete object occupies the start of the region, it can provide that its subobjects are within the region, but not the other way around.

@jensmaurer
Copy link
Member

That would be an incorrect rule.

Assuming sizeof(int) == 4, another possibility (beyond the ones I mentioned earlier) is to create four (distinct) complete unsigned char objects in the storage, only one of which is at the start of the storage (obviously). This is why [intro.object] p10 talks about "sets of objects".

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

That would be an incorrect rule.

Assuming sizeof(int) == 4, another possibility (beyond the ones I mentioned earlier) is to create four (distinct) complete unsigned char objects in the storage, only one of which is at the start of the storage (obviously). This is why [intro.object] p10 talks about "sets of objects".

If I express correctly, I don't think they will conflict. assumed to have their address to be the address of the start of the region means the mentioned objects are eligible to be but they do not actually all locate at the address. Once we determine one of them is the suitable created object, the other objects that would be eligible to be are in the other addresses of the region as per [intro.object] p9. Specifically, use your above example, each complete object of type unsigned char, named o1, o2, o3, o4, are all eligible to/can be assumed to have their address at the start of the region, but if o1 is the expected suitable created object, only o1 has its address at the start of the region.

@jensmaurer
Copy link
Member

jensmaurer commented Mar 11, 2023

No, disjoint objects can't have the same address when their lifetimes overlap.

Thus, under a given scenario, o1 ... o4 can't all be at the start of the region, only one of them can.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

No, disjoint objects can't have the same address when their lifetimes overlap.

Thus, under a given scenario, o1 ... o4 can't all be at the start of the region, only one of them can.

Isn't it what I meant in the above comment? Say p1, p2, p3, p4, where p1, p2, and p3 are eligible to participate in the election of the chair, this means we do not consider p4, p4 is excluded, "eligible to be" means they can be considered but only one of them will be selected as the chair.

@jensmaurer
Copy link
Member

Isn't it what I meant in the above comment?

I don't know what you meant; at least I cannot read that from the words of your proposed rule.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

Isn't it what I meant in the above comment?

I don't know what you meant; at least I cannot read that from the words of your proposed rule.

So, how about this proposed wording?

only one of the complete objects that are implicitly created objects can be considered its address as the address of the start of the region for the purpose of determining whether it is a suitable created object.

@jensmaurer
Copy link
Member

No, that also doesn't work, because (in my example) the objects o2, ..o4 might be implicitly created, but they will never be the "suitable created object" (because they're not at the start of the region of storage).

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

No, that also doesn't work, because (in my example) the objects o2, ..o4 might be implicitly created, but they will never be the "suitable created object" (because they're not at the start of the region of storage).

Why o2 cannot be the suitable created object? o1, o3, o4 will be located at the subsequence address of the region, and so forth. [intro.object] p11 says

If multiple such pointer values would give the program defined behavior, it is unspecified which such pointer value is produced.

IIUC, this means the pointer value can point to o1, o2, o3, or o4, once one of them is the suitable created object then the others won't be.

@jensmaurer
Copy link
Member

Sure, if you feel renumbering makes a difference. (I thought we'd number the objects in increasing address order to reduce on irrelevant dimension of freedom, but whatever.)

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 11, 2023

Sure, if you feel renumbering makes a difference. (I thought we'd number the objects in increasing address order to reduce on irrelevant dimension of freedom, but whatever.)

I just give every object a unique name for convenient discussion, the number is irrelevant to the address. If it makes misleading, then we can name them as oa, ob, oc, od. So, the proposed wording could be:

only the complete object in the set can be considered its address as the address of the start of the region for the purpose of determining whether it is a suitable created object.

@jensmaurer
Copy link
Member

jensmaurer commented Mar 11, 2023

That's also not correct. If you have a pointer-interconvertible subobject (which has the same address as the complete object), that one can also serve as the "suitable created object". We really mean "object" here, not "complete object".

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 12, 2023

That's also not correct. If you have a pointer-interconvertible subobject (which has the same address as the complete object), that one can also serve as the "suitable created object". We really mean "object" here, not "complete object".

I think [expr.static.cast] p14 can cover the case without the need to be extra mentioned in the supplementary rule. The supplementary rule tries to give a set of objects where any one of them is reasonable to be considered as located at the start of the region, which can provide that all its subobjects are within the region. Or, we just need to say:

Only one of the complete objects in the set and the subobjects thereof that would have the same address as that of the complete object are considered when assuming which objects whose address are the address of the start of the region.

[Note: The pointer-interconvertible subobject thereof can also have its address at the start of the region if the containing object is a suitable created object --- end note]

That is, thinking that the complete object in the set is reasonable to have its address at the start of the region, other cases can be proved by other rules defined in the document, such as pointer-interconvertible subobject can have the same address as the containing object.

The purpose of the supplementary rule is to form a set of objects from the set of implicitly created objects where any one thereof is reasonable to have its address at the start of the region anyway.

Moreover, a complete object is only a sufficient condition of being an object whose address is the address of the start of the region, This is similar to:

Say primary-expression is an expression, does not mean any expression must be a primary-expression.


If we don't give a set of objects that can have the address of the start of the region, then we lack the formal wording to interpret why the B subobject cannot have that address, as mentioned in #5630 (comment)

@frederick-vs-ja
Copy link
Contributor

Only one of the complete objects in the set and the subobjects thereof that would have the same address as that of the complete object are considered when assuming which objects whose address are the address of the start of the region.

This seems redundant, as "having the same address" should be an equivalence relationship and thus transitive. I think it's redundant to say "complete object", because whenever a subobject has the same address as the start of the region, so does its complete object.

If we don't give a set of objects that can have the address of the start of the region, then we lack the formal wording to interpret why the B subobject cannot have that address, as mentioned in #5630 (comment)

This seemingly reveals a more general issue. Given an A object is implicitly created, I believe the B subobject must have a higher address that that of the int subobject, and thus can't be the address of start of the region.

However, the order of addresses doesn't seem clearly specified. IMO it should be consistent with [expr.rel]/4, but there seems nothing clarifying that "p > q implies that the address of the byte represented by p is higher than that represented by q" (not vice versa, due to unspecified cases involving different base class subobjects).

@jensmaurer
Copy link
Member

However, the order of addresses doesn't seem clearly specified. IMO it should be consistent with [expr.rel]/4, but there seems nothing clarifying that "p > q implies that the address of the byte represented by p is higher than that represented by q" (not vice versa, due to unspecified cases involving different base class subobjects).

I think there are enough rules to make that true.

First, each object has an object representation per [basic.types.general] p4: "The object representation of an object of type T is the sequence of N unsigned char objects taken up by the object of type T, where N equals sizeof(T)".

We can compare the addresses (of an object or subobject with one of the array elements of the object representation) using ==, and [expr.rel] says a > b within an array (such as the array of unsigned char that is the object representation) is index-ordered.

Taken together, I think that means p > q (for p and q pointing to somewhere within the same complete object) implies the address represented by p is greater/later than the address represented by q.

And the smallest such address for an object is the address of the "first byte in memory in occupies".

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 12, 2023

This seems redundant, as "having the same address" should be an equivalence relationship and thus transitive. I think it's redundant to say "complete object", because whenever a subobject has the same address as the start of the region, so does its complete object.

No, the rule gives a constraint to specify which objects can be supposed to be candidates of the suitable created object. First, we use "complete object" to give the constraint, which can guarantee all subobjects thereof are within the allocated region, if without this constraint, then arbitrary objects that are implicitly created may be supposed to be the suitable created object, otherwise we should explicitly specify which objects in the region can have the address of the start of the region.

For the "subobjects thereof that would have the same address as that of the complete object", it is not redundant, it covers the case mentioned by @jensmaurer

If you have a pointer-interconvertible subobject (which has the same address as the complete object), that one can also serve as the "suitable created object".

Actually, "pointer-interconvertible" is transitive, a complete object and all subobjects pointer-interconvertible with it will have the same address. So, simply speaking, all complete objects are meaningful candidates for the suitable created object, and these corresponding subobjects are so, eventually, we will select one from them to be the suitable created object if the selection gives the program a defined behavior. This will solve the questions: 1. which objects whose address is the address of the start of the region is underspecified so that we don't know which objects can become the suitable created object. 2. why B subobject cannot be the suitable created object when we don't specify which objects have the address of the start of the region.

@frederick-vs-ja
Copy link
Contributor

  1. why B subobject cannot be the suitable created object when we don't specify which objects have the address of the start of the region.

I don't think this need an additional rule. If the B subobject were a suitably created object, then the address of the A complete object would be outside of the region, which is contradictory.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 12, 2023

  1. why B subobject cannot be the suitable created object when we don't specify which objects have the address of the start of the region.

I don't think this need an additional rule. If the B subobject were a suitably created object, then the address of the A complete object would be outside of the region, which is contradictory.

Actually, the issue is "the object whose address is the address of the start of the region" the wording is as the restriction/condition for becoming a suitable created object, as said in the above comment. Only if something satisfies a certain condition will it get a corresponding result. The condition is "whose address is the start of the region", the result is it is a suitable created object. The proposed wording tries to clarify which objects are suitable candidates for becoming the suitable created object, given this candidate set, every object in the set can be selected as the suitable created object if that selection would give the program a defined behavior. Moreover, the wording tries to give the source/information for "the object whose address is the start of the region". That is, any of the objects in the set can be supposed to have its address at the start of the region before determining the suitable created object.


If we do not have any information about the address of every implicitly created object, you should interpret why a certain object is a suitable created object when we impose the restriction "whose address is the address of the start of the region"

These operations select one of the implicitly-created objects whose address is the address of the start of the region of storage

Which objects they are, and which rule in the document says their address is the start of the region of storage?

@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented Mar 12, 2023

An object of an implicit-lifetime type can be created everywhere within the region, given the alignment and the remaining size after the address are suitable for its type.

Which objects they are, and which rule in the document says their address is the start of the region of storage?

I believe when you identify a certain implicitly created object, you have to specify

  • at which offset
    • its outermost complete object is created in the region, or
    • its complete object is created in the array, if the storage of that complete is provided by some array, and
  • the type of that object and every enclosing object, and
  • whether the object is a base class subobject, and
    • what the particular member is when the object is a member subobject, or
    • the index in the array when the object is an element object.

Otherwise, it's hard to say an object is identified, and we probably can't start to say "a certain object".

As a result, I think whether the address of such a given object is the start of the region can be deduced from the process of the identification, and no more wording is needed.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

As a result, I think whether the address of such a given object is the start of the region can be deduced from the process of the identification, and no more wording is needed.

When a conclusion/result is based on whether a condition is true, the condition should either:

  • The truth of the condition is explicitly specified somewhere
  • it can be deduced/proved by other explicitly specified statements / proved conditions

Give a simple example

The number whose value is greater than 0 is suitable whatever...

It can be translated to If x > 0, x is suitable whatever. For this example, if you say x is suitable whatever..., you should either show the explicitly specified condition somewhere or prove the condition is true by other conditions. For example, if there is a statement that says: x -2 > 0, so you can prove x > 2 with the statement, so you can indirectly prove x > 0 is true, so x is suitable whatever...

In the current draft, we don't have any conditions mentioned in the list. If by your interpretation, the wording "whose address is the address of the start of the region" should be changed to "if its address can be assumed to be the address of the start of the region".

@frederick-vs-ja
Copy link
Contributor

frederick-vs-ja commented Mar 13, 2023

What are the meaning and intent of "can be assumed"? I don't see the necessity not to say the plain "if its address is ...".

I think it's sufficient to make clarification like this.

Add a paragraph between [intro.object] p10 and p11:

X. When implicitly creating objects within a specified region of storage, every implicitly-created object whose address is the address of the start of the region of storage is a suitable created object.

Change p11 as indicated and make the term "suitable created objects" not introduced here:

  1. [...] These operations select one of suitable created objects the implicitly-created objects whose address is the address of the start of the region of storage, [...]

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

every implicitly-created object whose address is the address of the start of the region of storage

Again, how do you determine which implicitly-created objects' address is the address of the start of the region of storage and which are not? where is the rule you rely on?

@frederick-vs-ja
Copy link
Contributor

Again, how do you determine which implicitly-created objects' address is the address of the start of the region of storage and which are not? where is the rule you rely on?

This can be deduced from the identifcation of that object as I said before. If you start to talk about a certain object in some way, the way you specify the object already indicates whether the address of the object is the address of the start of the region of storage.

There might be uncertainty in non-pointer-interconvertible cases, but I think this should belong to another issue.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

If you start to talk about a certain object in some way, the way you specify the object already indicates whether the address of the object is the address of the start of the region of storage.

No, we just give a constraint set to specify the possible candidates, as for which object is selected from the set, it depends on what you want the program to do. It is similar to that we give all possible implicitly created objects the constraint that they shall have the implicitly-lifetime type, using which set of the implicitly created objects depends on you, we didn't concretely specify which set it is.

@frederick-vs-ja
Copy link
Contributor

Given every specified possible set of implicitly created objects, I think we can determine the subset of suitable created objects by identification of each object in the original set.

When attempting to access suitable created objects of expected types, the requirements on well-definedness restrict the possiblities of the sets of implicitly created objects, by requiring each of them to have a valid subset of suitable created objects.

I think the current wording is probably sufficient to imply this.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

When attempting to access suitable created objects of expected types, the requirements on well-definedness restrict the possiblities of the sets of implicitly created objects, by requiring each of them to have a valid subset of suitable created objects.

say p -> q is true, you should prove p is true, then q is true. You cannot conversely prove it. For example:

A class whose definition is reachable is complete

Test obj; 

For this example, the class type Test shall be a complete type, you should first prove the definition of Test is reachable, then you can say Test is a complete class type. The rule above is the proof you will use to prove Test is complete.

But, you shouldn't say: the declaration needs to be well-formed, so the class type should be complete, hence the class definition is reachable, so the declaration is well-formed. This is not the correct way to prove it.

So, even with your way, namely, the identification of the object, that is, we should remove all these objects that cannot have their address at the start of the region, then all remaining objects can be. You should prove why these objects cannot have their address at the start of the region by relying on the formal rule. Or, even you should prove the program is "well-definedness" if we use or do not use these objects.


The bullet you wrote in #5630 (comment) is a way of using the formal rule to prove which objects cannot have their address at the start of the region as if the bullet were the formal rule, anyway, we lack the wording like the bullet in the draft.

@frederick-vs-ja
Copy link
Contributor

The bullet you wrote in #5630 (comment) is a way of using the formal rule to prove which objects cannot have their address at the start of the region as if the bullet were the formal rule, anyway, we lack the wording like the bullet in the draft.

It sounds to me that you implied that without such a formal rule we can't even tell one implicitly created object from another in some cases. Did you mean that when one says an unsigned char object at offset 0 while another says an unsigned char object at offset 1, a rule implying that they say different objects is missing?

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

Did you mean that when one says an unsigned char object at offset 0 while another says an unsigned char object at offset 1, a rule implying that they say different objects is missing?

No, I didn't say that. I said that the formal rules that are used to prove whether an object whose address is the start of the region or not are missing. Similarly to this, we say a class whose definition is reachable at point P is XXX, we should prove whether its definition is reachable at point P, and in order to prove it, we should use [module.reach] p3, in order to prove [module.reach] p3.1 describes the case, we should prove: D appears prior to P in the same translation unit, in order to prove D appears prior to P, we should check [basic.lookup.general] p2, which defines how a declaration precedes P, then if all of these can be proved true, then we say the definition of the class is reachable at point P, so the class is XXX, this is the justification process.


So, for "a class whose definition is reachable at point P is XXX", the proving process is so, why do you think we do not need to prove "an object whose address is the start of the region"? why do you think we don't need to base the formal rule to prove it?

@frederick-vs-ja
Copy link
Contributor

So, for "a class whose definition is reachable at point P is ...", the proving process is so, why do you think we do not need to prove "an object whose address is the start of the region"? why do you think we don't need to base the formal rule to prove it?

I don't think we don't need to prove it. I think the rule is already present, because I think we have to identify an implicitly created object in the way said in #5630 (comment) or some similar way. I believe without this we can't even say why one is talking about some given object but not another.

In other words, there is probably no way in which one can specify a certain implicitly created object without providing sufficient information to determine whether its address is the start of the region, except for some non-pointer-interconvertible cases that possibly need clarification.

I think a counterexample is needed for making progress.

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 13, 2023

I think the rule is already present, because I think we have to identify an implicitly created object in the way said in #5630 (comment) or some similar way.

Identifying an implicitly created object is a subjective opinion, you say the object a can have its address at the start of the region, then it can be a suitable created object. However, "the implicitly-created objects whose address is the address of the start of the region of storage", the "whose address is ..." imposes an objective fact.

For the same example:

malloc(128);

You say you want the suitable created object that is the object of type A, and if that object has its address at the start of the region and it won't violate anything, then it is considered to be an object whose address is the start of the region. I say I want an object of type char and it's also true. The third person says it's an object of type B and it's also true with his opinion, and so forth. However, we know two objects cannot have the same address unless it satisfies [intro.object] p9 or they are pointer-interconvertible. So, from different people's perspectives, we don't agree with each other that his expected object has its address at the start of the region unless anyone can prove to others the object's address is the start of the region.

Hence, I think this issue is we should define the set of candidates of the suitable created object. Then any one of them will be selected as the suitable created object will be all reasonable because we can achieve a consensus on the set of candidates. What you said in #5630 (comment) does prove what I proposed, namely, which objects are candidates of the suitable created objects. For instance

at which offset

  • its outermost complete object is created in the region

This does imply: These objects that would make their complete objects out of the region if they had been located at the start of the region are not eligible to be candidates of the suitable created object.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants