[cfe-commits] Vtordisp for MS ABI.

John McCall rjmccall at apple.com
Tue Jun 5 00:44:03 PDT 2012


On May 30, 2012, at 4:46 AM, r4start wrote:
> On 30/05/2012 07:06, John McCall wrote:
>> Is this the rule used by MSVC?  For example, does a vtordisp still get emitted even if a ctor "obviously" doesn't call any virtual functions, like if it's defined in the class definition and obviously empty?  Please test both an empty ctor and an empty dtor.
>> 
> I think MSVC doesn`t analyze ctor or dtor body.

Excellent.  That's very good.

>> Please also add testcases verifying that we do the right thing in further-derived classes that provide ctors.  For example:
>>   struct A { virtual void foo(); };
>>   struct B : virtual A { virtual void foo(); }; // no vtordisp
>>   struct Test1 : B { Test1(); };
>>   struct Test2 : virtual B { Test2(); };
>>   struct Test3 : B { Test3(); virtual void foo(); };
>>   struct Test4 : virtual B { Test4(); virtual void foo(); };
>> 
> Test3 and Test4 have vtordisps for virtual base A. At now clang(with my patch, I test this on my working copy) add vtordisp only in Test4 for B, not for A.
> I add new patch. Problem was in undecidedVBases.erase(overriddenBase). In Test3 overriddenBase == B but undecidedVBases contains A.

Mmm, I'm not sure about this fix.  I suspect that the rule here is that a class C requires a vtordisp for a virtual base B if:
 1) it has a user-defined constructor or destructor and
 2) it declares a method which overrides a method declared by that virtual base or one of its non-virtual bases, directly or no.

This all prompts some more interesting questions which I'd appreciate you running.  Given the following:
  struct A { virtual void foo(); };
  struct B : A {};
  struct C : virtual B { virtual void foo(); };

This tests that the rule applies to "virtual subobjects".  I think we know this already.
  struct Test1 : C { Test1(); virtual void foo(); }; // this should need a vtordisp for B

I'm very suspicious of your "first declaration" test;  this should be sufficient as a counter-example, but the problem is deeper.  It's more that we have to look everywhere in the hierarchy to see what's overridden by the method.
  struct Test2a : C { virtual void foo(); };
  struct Test2 : Test2 { Test2(); virtual void foo(); }; // this should need a vtordisp for B

This is just testing whether we can "break up" our class.  Basically, should criterion (2) above be "C declares a method..." or "C's construction vtable declares a method..."?  For correctness, I think the answer *should* be the latter, but I don't know whether MSVC actually does that, because it requires the emission of Test3's vtable to create a thunk for Test3a::foo(), which might be problematic.
  struct Test3a : C { virtual void foo(); };
  struct Test3 : Test3a { Test3(); };

John.



More information about the cfe-commits mailing list