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.add] p4 Whether the array object should be during its lifetime or not? #382

Closed
xmh0511 opened this issue Jul 30, 2023 · 16 comments
Closed

Comments

@xmh0511
Copy link

xmh0511 commented Jul 30, 2023

Full name of submitter (unless configured in github; will be published with the issue): Jim X

[expr.add] p4 says

When an expression J that has integral type is added to or subtracted from an expression P of pointer type, the result has the type of P.

  • [...]
  • Otherwise, if P points to an array element i of an array object x with n elements ([dcl.array]),69 the expressions P + J and J + P (where J has the value j) point to the (possibly-hypothetical) array element i+j of x if 0≤i+j≤n and the expression P - J points to the (possibly-hypothetical) array element i−j of x if 0≤i−j≤n.

The rule does not say the array object x should be during its lifetime, consider this example:

    int arr[2];
    auto P = arr;
    new (P) int const[2]{0,0};
    new (P) int[2];
    P+ 1;  // #1

After these operations, P points to an array object whose lifetime has ended. So, can P at #1 be called to point to the first element of an array that was an array object? Since [basic.life] p4 says:

The properties ascribed to objects and references throughout this document apply for a given object or reference only during its lifetime.

So, whether an "object" can be called object after its lifetime has ended?

@jensmaurer
Copy link
Member

That's not something we need to answer. This talks about "properties ascribed to objects and references", and one property is that you can do pointer arithmetic on pointers to those. If an object is out-of-lifetime, you lose that property (unless it's a property in the special lists in [basic.life]).

The example you gave thus has undefined behavior.

I'm not seeing a defect that needs fixing.

@xmh0511
Copy link
Author

xmh0511 commented Jul 30, 2023

That's not something we need to answer. This talks about "properties ascribed to objects and references", and one property is that you can do pointer arithmetic on pointers to those. If an object is out-of-lifetime, you lose that property (unless it's a property in the special lists in [basic.life]).

The example you gave thus has undefined behavior.

I'm not seeing a defect that needs fixing.

If the pointer arithmetic has undefined behavior, we should explicitly add it to the list [basic.life] p6.

@jensmaurer
Copy link
Member

jensmaurer commented Jul 30, 2023

The list in [basic.life] p6 enumerates the things that you are allowed to do with an out-of-lifetime object. We don't have to do anything for things that are disallowed on an out-of-lifetime object.

@xmh0511
Copy link
Author

xmh0511 commented Jul 30, 2023

The list in [basic.life] p6 enumerates the things that you are allowed to do with an out-of-lifetime object.

The list in [basic.life] p6 says:

The program has undefined behavior if:

  • the pointer is used as the operand of a delete-expression,
  • [...]

The list enumerates what we are disallowed to do with the pointer.

@languagelawyer
Copy link

languagelawyer commented Jul 30, 2023

and one property is that you can do pointer arithmetic on pointers to those

Me and @zygoloid have consensus that pointer arithmetic on dead arrays is ok…

@jensmaurer
Copy link
Member

jensmaurer commented Jul 30, 2023

The list enumerates what we are disallowed to do with the pointer.

Ah, right, I was confused.

So, it's not in the list of "bad" things you can do with a pointer, so pointer arithmetic on a dead object is allowed.

(A pointer value becomes invalid if the storage goes away, not when the object lifetime ends.)

@xmh0511
Copy link
Author

xmh0511 commented Jul 30, 2023

The list enumerates what we are disallowed to do with the pointer.

Ah, right, I was confused.

So, it's not in the list of "bad" things you can do with a pointer, so pointer arithmetic on a dead object is allowed.

(A pointer value becomes invalid if the storage goes away, not when the object lifetime ends.)

Ok, so how about the issue in [basic.life] p4? At least, it ever can make us agree the dead array objects lose the pointer arithmetic, which can embody that the wording is not clear about the extent of "properties".

@frederick-vs-ja
Copy link

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

@jensmaurer
Copy link
Member

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

I don't think so. This is solely about converting a void* to a T* at compile time, when the object pointed to is actually a T.

@frederick-vs-ja
Copy link

I don't think so. This is solely about converting a void* to a T* at compile time, when the object pointed to is actually a T.

This part is also addressed by P2738R1 and has been adopted for C++26.

IIUC P2747 is also exploring a way such that starting the lifetime of an element of an array which is a union variant member also starts the lifetime of that array.

@xmh0511
Copy link
Author

xmh0511 commented Oct 26, 2023

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

where is this part in your linked paper? I didn't find them.

@xmh0511
Copy link
Author

xmh0511 commented Oct 26, 2023

@jensmaurer Regarding we also have some indetermination opinions about this issue, for example:

That's not something we need to answer. This talks about "properties ascribed to objects and references", and one property is that you can do pointer arithmetic on pointers to those. If an object is out-of-lifetime, you lose that property (unless it's a property in the special lists in [basic.life]).

The example you gave thus has undefined behavior.

So, it's not in the list of "bad" things you can do with a pointer, so pointer arithmetic on a dead object is allowed.

Me and @zygoloid have consensus that pointer arithmetic on dead arrays is ok…

what's the reason why you two have tha consensus?

In addition, can a dead array object be called an array object? After all, [expr.add] p4 says that the pointer points to an element of an array object, shall we reopen this issue and clarify these issues?

@frederick-vs-ja
Copy link

frederick-vs-ja commented Oct 26, 2023

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

where is this part in your linked paper? I didn't find them.

I think this part is related - we can't even locate a suboject of a non-living array if pointer arithmetic is undefined (except for the first element).

Lastly, this paper proposes that placement new on an array alternative of a union implicitly starts the lifetime of the whole array alternative. This seems consistent with the implicit-lifetime-type rule that we have for arrays, and is the minimal change required to allow static_vector to work and to allow user implementations of uninitialized<T>. I’m not proposing std::uninitialized<T> specifically because I don’t think it’s strictly necessary, and the shape of it will largely end up depending on the discussion around JF’s paper - which is otherwise completely unrelated to this paper.

@xmh0511
Copy link
Author

xmh0511 commented Oct 26, 2023

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

where is this part in your linked paper? I didn't find them.

I think this part is related - we can't even locate a suboject of a non-living array if pointer arithmetic is undefined (except for the first element).

Lastly, this paper proposes that placement new on an array alternative of a union implicitly starts the lifetime of the whole array alternative. This seems consistent with the implicit-lifetime-type rule that we have for arrays, and is the minimal change required to allow static_vector to work and to allow user implementations of uninitialized<T>. I’m not proposing std::uninitialized<T> specifically because I don’t think it’s strictly necessary, and the shape of it will largely end up depending on the discussion around JF’s paper - which is otherwise completely unrelated to this paper.

Sorry, I cannot read any relevant information about why dead array can do pointer arithmetic operations in this paragraph.

@frederick-vs-ja
Copy link

Sorry, I cannot read any relevant information about why dead array can do pointer arithmetic operations in this paragraph.

I originally said that

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

but not "it says why dead array can do what".

Such assumption can also be found in X* x = std::construct_at(&storage.data[0], i);.

@xmh0511
Copy link
Author

xmh0511 commented Oct 26, 2023

Sorry, I cannot read any relevant information about why dead array can do pointer arithmetic operations in this paragraph.

I originally said that

P2747R0 touches this area. IIUC it does assume that pointer arithmetic on a non-living array is OK.

but not "it says why dead array can do what".

Such assumption can also be found in X* x = std::construct_at(&storage.data[0], i);.

That is, we lack a formal wording to claim this point, isn't it.

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

4 participants