Date: Wed, 15 Jan 2014 21:48:26 +0000
Richard, I'm not sure I understand your position... Given the following complete program ...
struct B { int i; };
struct D : B { };
int main() {
B b; // line X
}
... are you actually saying that line X starts the lifetime of an object of type D? or just setting up a strawman? (Sorry, I really couldn't tell.)
If yes, then given the following complete program ...
struct C { long long i; };
int main() {
C c; // line Y
}
... are you saying that line Y could start the lifetime of an object of type D (which is not mentioned in the code), double, shared_ptr<widget>, or any other type than C, as long as the size of that other type is the same or less than sizeof(C)?
Herb
________________________________
From: ub-bounces_at_[hidden] <ub-bounces_at_[hidden]> on behalf of Richard Smith <richardsmith_at_[hidden]>
Sent: Monday, January 6, 2014 3:44 PM
To: WG21 UB study group
Subject: Re: [ub] type punning through congruent base class?
On Mon, Jan 6, 2014 at 10:22 AM, Jason Merrill <jason_at_[hidden]<mailto:jason_at_[hidden]>> wrote:
On 01/06/2014 04:26 AM, Fabio Fracassi wrote:
> if it is not (legal): could we make it legal or would we run afoul of
> the aliasing rules?
The access is not allowed by the aliasing rules in 3.10. But it seems
that this would be:
struct B {
int i;
};
struct D {
B bmem;
void foo() { /* access bmem.i */ }
};
B b;
reinterpret_cast<D&>(b).foo();
because B is a non-static data member of D, and 9.2/19 guarantees that
the address of D::bmem is the same as the address of the D object.
How is that fundamentally different? 9.3.1/2 makes that UB too, if 'reinterpret_cast<D&>(b)' does not refer to an object of type 'b'. And within D::foo, the implicit this->bmem would have the same problem.
If I might play devil's advocate for a moment...
struct B { int i; };
struct D : B {
void foo();
};
B b;
I claim this line starts the lifetime of an object of type D. Per [basic.life]p1, the lifetime of an object of type 'D' begins when storage with the proper alignment and size for type T is obtained (which "B b" happens to satisfy). The object does not have non-trivial initialization, so the second bullet does not apply.
(This is the same argument that makes this valid:
D *p = (D*)malloc(sizeof(D));
p->foo();
... so any counterargument will need to explain why the two cases are fundamentally different.)
Then:
reinterpret_cast<D&>(b).foo();
... is valid, because the cast produces the same memory address, and that memory address contains an object of type 'D' (as claimed above).
struct B { int i; };
struct D : B { };
int main() {
B b; // line X
}
... are you actually saying that line X starts the lifetime of an object of type D? or just setting up a strawman? (Sorry, I really couldn't tell.)
If yes, then given the following complete program ...
struct C { long long i; };
int main() {
C c; // line Y
}
... are you saying that line Y could start the lifetime of an object of type D (which is not mentioned in the code), double, shared_ptr<widget>, or any other type than C, as long as the size of that other type is the same or less than sizeof(C)?
Herb
________________________________
From: ub-bounces_at_[hidden] <ub-bounces_at_[hidden]> on behalf of Richard Smith <richardsmith_at_[hidden]>
Sent: Monday, January 6, 2014 3:44 PM
To: WG21 UB study group
Subject: Re: [ub] type punning through congruent base class?
On Mon, Jan 6, 2014 at 10:22 AM, Jason Merrill <jason_at_[hidden]<mailto:jason_at_[hidden]>> wrote:
On 01/06/2014 04:26 AM, Fabio Fracassi wrote:
> if it is not (legal): could we make it legal or would we run afoul of
> the aliasing rules?
The access is not allowed by the aliasing rules in 3.10. But it seems
that this would be:
struct B {
int i;
};
struct D {
B bmem;
void foo() { /* access bmem.i */ }
};
B b;
reinterpret_cast<D&>(b).foo();
because B is a non-static data member of D, and 9.2/19 guarantees that
the address of D::bmem is the same as the address of the D object.
How is that fundamentally different? 9.3.1/2 makes that UB too, if 'reinterpret_cast<D&>(b)' does not refer to an object of type 'b'. And within D::foo, the implicit this->bmem would have the same problem.
If I might play devil's advocate for a moment...
struct B { int i; };
struct D : B {
void foo();
};
B b;
I claim this line starts the lifetime of an object of type D. Per [basic.life]p1, the lifetime of an object of type 'D' begins when storage with the proper alignment and size for type T is obtained (which "B b" happens to satisfy). The object does not have non-trivial initialization, so the second bullet does not apply.
(This is the same argument that makes this valid:
D *p = (D*)malloc(sizeof(D));
p->foo();
... so any counterargument will need to explain why the two cases are fundamentally different.)
Then:
reinterpret_cast<D&>(b).foo();
... is valid, because the cast produces the same memory address, and that memory address contains an object of type 'D' (as claimed above).
Received on 2014-01-15 23:03:26