On Fri, Apr 12, 2013 at 2:42 PM, John McCall <[email protected]> wrote:
> On Apr 12, 2013, at 10:59 AM, Reid Kleckner <[email protected]> wrote:
>> On Wed, Apr 10, 2013 at 4:12 PM, John McCall <[email protected]> wrote:
>>> On Apr 6, 2013, at 3:44 PM, Reid Kleckner <[email protected]> wrote:
>>>> + virtual void mangleCXXVBTable(const CXXRecordDecl *Derived,
>>>> + llvm::ArrayRef<const CXXRecordDecl *>
>>>> BasePath,
>>>
>>> This needs to be a path of CXXBaseSpecifier*s. One, that's probably
>>> more straightforward to create, and two, there's an ambiguity here that
>>> it'd clean up.
>>
>> Should I be rolling my own recursion here to discover all unique
>> subobjects, or is there some method on CXXBasePaths I should be
>> calling to generate these?
>
> A CXXBasePathElement stores the Base.
>
>>> For example:
>>> struct A { int x; };
>>> struct B : virtual A {}; // vbptrs: B
>>> struct C : virtual B {}; // vbptrs: C, virtual B in C
>>> struct D : B, C {}; // vbptrs: B in D, C in D, virtual B in D
>>>
>>> Incidentally, how would these actually be mangled?
>>
>> That program gives:
>> error C2584: 'D' : direct base 'B' is inaccessible; already a base of 'C'
>
> Oh, right, yes, sorry.
Re-ordering B and C gets through with a warning instead of an error:
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual B { int c; };
struct D : C, B { int d; };
D d;
warning C4584: 'D' : base-class 'B' is already a base-class of 'C'
I'm still stumped on the logic for the symbols this produces though:
# B's vbtable for itself
??_8B@@7B@
# C's vbtables, self then for B
??_8C@@7B0@@
??_8C@@7BB@@@
# D's vbtables.
??_8D@@7BC@@@ # vbptr inside C
??_8D@@7B@ # vbptr inside non-virtual B
??_8D@@7BB@@@ # vbptr inside morally virtual B
I would expect this to be mangled as:
??_8D@@7BC@@@ # same
??_8D@@7BB@@@ # because there is ambiguity between B and C
??_8D@@7BB@@C@@@ # same
Adding another level of non-virtual inheritance gives deeper paths:
struct E : D, C, B { int e; };
??_8E@@7BC@@D@@@ # vbptr in C in D in E
??_8E@@7BD@@@ # vbptr in non-virtual B in D in E
??_8E@@7BC@@@ # vbptr in C in E
??_8E@@7BB@@@ # vbptr in non-virtual B in E
??_8E@@7BB@@D@@@ # vbptr in virtual B in C in D in E
It seems weird to me that the symbol for vbtables installed inside
morally virtual bases includes non-virtual path steps. That means the
symbol depends on which path you follow to find the virtual base.
That said, the path order is fairly obvious.
Any idea what's going on here? What's special about non-virtual B's
vbtable inside D that makes it's symbol shorter? Previously I
expected there to be something special about the name of the first
vbtable occurring in non-virtual bases, but this doesn't fit because
the non-virtual B subobject comes after C in D.
I attached the test case that I've been developing. It's a work in
progress, but it can answer some questions if you're curious.
// RUN: %clang_cc1 %s -fno-rtti -cxx-abi microsoft -triple=i386-pc-win32 -emit-llvm -o %t
// I can't seem to get the tests in order, so I did this.
// RUN: FileCheck %s < %t
// RUN: grep Test1 %t | FileCheck --check-prefix=TEST1 %s
// RUN: grep Test2 %t | FileCheck --check-prefix=TEST2 %s
// RUN: grep Test3 %t | FileCheck --check-prefix=TEST3 %s
// RUN: grep Test4 %t | FileCheck --check-prefix=TEST4 %s
// RUN: grep Test5 %t | FileCheck --check-prefix=TEST5 %s
// RUN: grep Test6 %t | FileCheck --check-prefix=TEST6 %s
// RUN: grep Test7 %t | FileCheck --check-prefix=TEST7 %s
// RUN: grep Test8 %t | FileCheck --check-prefix=TEST8 %s
// RUNX: grep Test9 %t | FileCheck --check-prefix=TEST9 %s
// RUN: grep Test10 %t | FileCheck --check-prefix=TEST10 %s
// RUN: grep Test11 %t | FileCheck --check-prefix=TEST11 %s
// RUN: grep Test12 %t | FileCheck --check-prefix=TEST12 %s
namespace Test1 {
// Classic diamond, fully virtual.
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : virtual B, virtual C { int d; };
D d; // Force vbtable emission.
// Layout should be:
// D: vbptr D
// int d
// A: int a
// B: vbptr B
// int b
// C: vbptr C
// int c
// Test the vbptr initialization in the constructor. D should have 3 vbptrs.
// CHECK: define linkonce_odr x86_thiscallcc {{.*}} @"\01??0D@Test1@@QAE@XZ"({{.*}}) {{.*}} {
// CHECK: entry:
// CHECK: {{^.*:.*}}
// CHECK: %[[this_i8:.*]] = bitcast {{.*}} to i8*
// CHECK: %[[v0:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 0
// CHECK: %[[vbptr_D:.*]] = bitcast i8* %[[v0]] to [4 x i32]**
// CHECK: store [4 x i32]* @"\01??_8D@Test1@@7B01@@", [4 x i32]** %[[vbptr_D]]
// CHECK: %[[v1:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 12
// CHECK: %[[vbptr_B:.*]] = bitcast i8* %[[v1]] to [2 x i32]**
// CHECK: store [2 x i32]* @"\01??_8D@Test1@@7BB@1@@", [2 x i32]** %[[vbptr_B]]
// CHECK: %[[v2:.*]] = getelementptr inbounds i8* %[[this_i8]], i64 20
// CHECK: %[[vbptr_C:.*]] = bitcast i8* %[[v2]] to [2 x i32]**
// CHECK: store [2 x i32]* @"\01??_8D@Test1@@7BC@1@@", [2 x i32]** %[[vbptr_C]]
// CHECK: }
// TEST1: @"\01??_8D@Test1@@7B01@@" = [[linkage:linkonce_odr unnamed_addr constant]] [4 x i32] [i32 0, i32 8, i32 12, i32 20]
// TEST1: @"\01??_8D@Test1@@7BB@1@@" = [[linkage]] [2 x i32] [i32 0, i32 -4]
// TEST1: @"\01??_8D@Test1@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 -12]
// TEST1: @"\01??_8C@Test1@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
// TEST1: @"\01??_8B@Test1@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
}
namespace Test2 {
// Classic diamond, only A is virtual.
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B, C { int d; };
D d; // Force vbtable emission.
// Layout should be:
// B: vbptr B
// int b
// C: vbptr C
// int c
// D: int d
// A: int a
// TEST2: @"\01??_8D@Test2@@7BB@1@@" = [[linkage:linkonce_odr unnamed_addr constant]] [2 x i32] [i32 0, i32 20]
// TEST2: @"\01??_8D@Test2@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 12]
// TEST2: @"\01??_8C@Test2@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
// TEST2: @"\01??_8B@Test2@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
}
namespace Test3 {
struct A { int a; };
struct B { int b; };
struct C : virtual A, virtual B { int c; };
C c;
// TEST3: @"\01??_8C@Test3@@7B@" = [[linkage:linkonce_odr unnamed_addr constant]] [3 x i32] [i32 0, i32 8, i32 12]
}
namespace Test4 {
// Test reusing a vbptr from a non-virtual base.
struct A { int a; };
struct B : virtual A { int b; };
struct C : B, virtual A { int c; };
C c; // Force vbtable emission.
// TEST4: @"\01??_8C@Test4@@7B@" = [[linkage:linkonce_odr unnamed_addr constant]] [2 x i32] [i32 0, i32 12]
// TEST4: @"\01??_8B@Test4@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
}
namespace Test5 {
// Test a non-virtual base with a virtual base that appears multiple times.
struct A { int a; };
struct B : virtual A { int b; };
struct C : B { int c; };
struct D : B, C { int d; };
D d; // Force vbtable emission.
// TEST5: @"\01??_8D@Test5@@7BB@1@@"
// TEST5: @"\01??_8D@Test5@@7BC@1@@"
// TEST5: @"\01??_8C@Test5@@7B@"
// TEST5: @"\01??_8B@Test5@@7B@"
}
namespace Test6 {
// Test that we skip unneeded base path component names. We don't need to
// include the name of a base class when its parent only uses single
// inheritance.
struct A { int a; };
struct B : virtual A { int b; };
struct C : B { int c; };
struct D : B, C { int d; };
struct E : D { int e; };
struct F : E, B, C { int f; };
struct G : F, virtual E { int g; };
G g;
// TEST6: @"\01??_8G@Test6@@7BB@1@E@1@F@1@@" =
// TEST6: @"\01??_8G@Test6@@7BC@1@E@1@F@1@@" =
// TEST6: @"\01??_8G@Test6@@7BB@1@F@1@@" =
// TEST6: @"\01??_8G@Test6@@7BC@1@F@1@@" =
// TEST6: @"\01??_8G@Test6@@7BB@1@E@1@@" =
// TEST6: @"\01??_8G@Test6@@7BC@1@E@1@@" =
// TEST6: @"\01??_8F@Test6@@7BB@1@E@1@@" = [[linkage:linkonce_odr unnamed_addr constant]] [2 x i32] [i32 0, i32 52]
// TEST6: @"\01??_8F@Test6@@7BC@1@E@1@@" = [[linkage]] [2 x i32] [i32 0, i32 44]
// TEST6: @"\01??_8F@Test6@@7BB@1@@" = [[linkage]] [2 x i32] [i32 0, i32 24]
// TEST6: @"\01??_8F@Test6@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 16]
// TEST6: @"\01??_8C@Test6@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 12]
// TEST6: @"\01??_8B@Test6@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
// TEST6: @"\01??_8E@Test6@@7BB@1@@" = [[linkage]] [2 x i32] [i32 0, i32 28]
// TEST6: @"\01??_8E@Test6@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 20]
// TEST6: @"\01??_8D@Test6@@7BB@1@@" = [[linkage]] [2 x i32] [i32 0, i32 24]
// TEST6: @"\01??_8D@Test6@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 16]
}
namespace Test7 {
// Test a non-virtual base which reuses the vbptr of another base.
struct A { int a; };
struct B { int b; };
struct C { int c; };
struct D : virtual A { int d; };
struct E : B, D, virtual A, virtual C { int e; };
E o;
// TEST7: @"\01??_8E@Test7@@7B@" = [[linkage:linkonce_odr unnamed_addr constant]] [3 x i32] [i32 0, i32 12, i32 16]
// TEST7: @"\01??_8D@Test7@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
}
namespace Test8 {
// Test a virtual base which reuses the vbptr of another base.
struct A { int a; };
struct B : virtual A { int b; };
struct C : B { int c; };
struct D : virtual C { int d; };
D o;
// TEST8: @"\01??_8D@Test8@@7B01@@" = [[linkage:linkonce_odr unnamed_addr constant]] [3 x i32] [i32 0, i32 8, i32 12]
// TEST8: @"\01??_8D@Test8@@7BC@1@@" = [[linkage]] [2 x i32] [i32 0, i32 -4]
// TEST8: @"\01??_8C@Test8@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 12]
// TEST8: @"\01??_8B@Test8@@7B@" = [[linkage]] [2 x i32] [i32 0, i32 8]
}
namespace Test9 {
// D has to add to B's vbtable because D has more morally virtual bases than B.
// D then takes B's vbptr and the vbtable is named for D, not B.
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual B { int c; };
struct BB : B { int bb; }; // Indirection =/
struct D : BB, C { int d; };
struct E : virtual D { };
E e;
// TEST9: @"\01??_8E@Test9@@7B01@@" =
// TEST9: @"\01??_8E@Test9@@7BD@1@@" =
// TEST9: @"\01??_8E@Test9@@7BC@1@@" =
// TEST9: @"\01??_8E@Test9@@7BB@1@@" =
// TEST9: @"\01??_8B@Test9@@7B@" =
// TEST9: @"\01??_8D@Test9@@7B@" =
// TEST9: @"\01??_8D@Test9@@7BC@1@@" =
// TEST9: @"\01??_8D@Test9@@7BB@1@@" =
// TEST9: @"\01??_8C@Test9@@7B01@@" =
// TEST9: @"\01??_8C@Test9@@7BB@1@@" =
// TEST9: @"\01??_8BB@Test9@@7B@" =
// @"\01??_8B@Test9@@7B@" =
// @"\01??_8C@Test9@@7B01@@" =
// @"\01??_8C@Test9@@7BB@1@@" =
// @"\01??_8BB@Test9@@7B@" =
}
namespace Test10 {
struct A { int a; };
struct B { int b; };
struct C : virtual A { int c; };
struct D : B, C { int d; };
D d;
// TEST10: @"\01??_8D@Test10@@7B@" =
// TEST10: @"\01??_8C@Test10@@7B@" =
}
namespace Test11 {
// Typical diamond with an extra single inheritance indirection for B and C.
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual A { int c; };
struct D : B { int d; };
struct E : C { int e; };
struct F : D, E { int f; };
F f;
// TEST11: @"\01??_8F@Test11@@7BD@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 28]
// TEST11: @"\01??_8F@Test11@@7BE@1@@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 16]
// TEST11: @"\01??_8E@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
// TEST11: @"\01??_8C@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
// TEST11: @"\01??_8D@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 12]
// TEST11: @"\01??_8B@Test11@@7B@" = linkonce_odr unnamed_addr constant [2 x i32] [i32 0, i32 8]
}
namespace Test12 {
// Another vbptr inside a virtual base.
struct A { int a; };
struct B : virtual A { int b; };
struct C : virtual B { int c; };
struct D : C, B { int d; };
D d;
// TEST12: @"\01??_8D@Test12@@7B@" =
// TEST12: @"\01??_8D@Test12@@7BC@1@@" =
// TEST12: @"\01??_8D@Test12@@7BB@1@@" =
// TEST12: @"\01??_8C@Test12@@7B01@@" =
// TEST12: @"\01??_8C@Test12@@7BB@1@@" =
// TEST12: @"\01??_8B@Test12@@7B@" =
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits