From Bugzilla Helper: User-Agent: Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0; NetCaptor 6.5.0PB8) Description of problem: G++3 gives wrong layout of class E object in the testcase below. 1. The testcase --------------- struct A { int a; }; struct B : public virtual A {}; struct C { long double c; }; struct D : public virtual C { int d; }; struct E : public B, public D { int e; }; 2. The issue ------------ Expected layout of class E on ia64 is the following: Offset Size Contents [0000] 8 B's virtual table pointer (B is the primary base for E) [0008] 8 D's virtual table pointer [0010] 4 D::d [0014] 4 Padding to round up D size to multiple of pointer align (8) [0018] 4 E::e [001c] 4 A::a [0020] 16 C::c But G++3 compiler gives another object layout for E: Offset Size Contents [0000] 8 B's virtual table pointer (B is the primary base for E) [0008] 8 Padding [0010] 8 D's virtual table pointer [0018] 4 D::d [001c] 4 E::e [0020] 4 A::a [0024] 12 Padding [0030] 16 C::c The layout is different and is wrong. 3. Details and analisis ----------------------- We see difference in three points here, all related to padding bytes added. I. Padding after B's virtual table pointer This is the major inconsistency. Let's see... The C++ ABI says [Chapter 2: Data Layout/2.4 Non-POD Class Types/II. Allocation of Members Other Than Virtual Bases]: "if D is not an empty base class (including all data members), start at offset dsize(C), incremented if necessary for alignment to nvalign(type(D)) for base classes or to align(type(D)) for data members. " In our case, nvalign(D) == 8, align(D) == 16. So, it looks like g++3 did increment address to keep 16-bytes alignment of class D. But this is valid for data members only and not for base classes. Such behaviour is wrong. Since D is the base class, it should be aligned to nvalign (D)==8 bytes within class E and there should not be any padding. In other words, g++3 erroneously uses align(D) instead of nvalign(D). II. No padding after D::d Class D is laying out using common rules. It means that D should be finalized either - rounded up to a non-zero multiple of align(D). g++3 does not perform this step for base classes. See Bugzilla Bug #64535 for details. III. Extra padding after A::a There is nothing wrong - C::c should be 16-byte aligned. Difference is just a side-effect of inconsistency listed above. Version-Release number of selected component (if applicable): How reproducible: Always Steps to Reproduce: It's not so easy to dump object as showed above. So we are using run-time test which checks offset of class D within the object E. It used to be sizeof(void *), i.e. D is comming right after class B, when B contains only the virtual table pointer. 1. Build attached fail.cpp test using simple command line g++3 fail.cpp 2. Run it ./a.out 3. Look for 'passed' word in the output Actual Results: failed D's offset is 16 expected 8 Expected Results: passed Additional info:
Created attachment 58005 [details] The testcase
Ok with g++ 3.2 on x86 at least
The given test case does pass with gcc 3.2, though the layout is slightly different than described. It's [000] vptr for B [008] vptr for D [010] D::d [014] E::e [018] A::a [020] C::c I.e. E is using the tail padding in D. I don't see anything wrong with this.