Currently, it's possible for relative vtables (RV) that fit precisely in a mergable constants group to not be collected by --gc-sections even when -fdata-sections is enabled. This results in some vtables that would normally be garbage collected to persist after linking, causing extra bloat in rodata.
This happens because constants that do not need relocations according to Constant::needsRelocation have the option of being placed into these .rodata.cstN sections. That is, a vtable can get placed into .section .rodata.cst16 rather than something like .section .rodata.{vtable} under -fdata-sections, and --gc-sections would not collect the vtable in .section .rodata.cst16.
Note that this doesn't affect vtables under the default Itanium ABI that *could* fit into one of these mergeable sections but *would* get placed only into .rodata. Example:
class A { public: virtual void func(); virtual void func2(); }; void A::func() {} void A::func2() {}
compiled with ./bin/clang++ -c /tmp/test.cc -target x86_64-linux-gnu -fno-pic -fno-rtti -fdata-sections -S -o - generates
.type _ZTV1A,@object # @_ZTV1A .section .rodata._ZTV1A,"a",@progbits .globl _ZTV1A .p2align 3 _ZTV1A: .quad 0 .quad 0 .quad _ZN1A4funcEv .quad _ZN1A5func2Ev .size _ZTV1A, 32
The only reason this isn't placed into .rodata.cst32 is because they need relocations according to Constant::needsRelocation (so they take a different branch from what relative vtables would), but because this is made with a static relocation model (non-PIC mode), the vtable can be safely placed in .rodata. This is a unique scenario that is only surfacing now from the RV work.
To keep this contained under the realm of RV changes, a simple fix would be to place these kinds of vtables in comdat groups when appropriate, then --gc-sections can collect them appropriately.