{"push_id":544688526,"size":1,"distinct_size":1,"ref":"refs/heads/master","head":"226ccdcbffaa1635f29d6a29699e7073332fe4e1","before":"72cc34c18a61325905c186f303e77a5f49bdba68","commits":[{"sha":"226ccdcbffaa1635f29d6a29699e7073332fe4e1","author":{"email":"0d2d6fe0cb2e9ade0d2bf90d72a72b8ac034ef0e@gmx.de","name":"Nico Weber"},"message":"Mark vtable used on explicit destructor definitions.\n\nThere are two things in a C++ program that need to read the vtable pointer:\nConstructors and destructors.  (A few other operations -- virtual calls,\ndynamic cast, rtti -- read the vtable pointer off a this pointer, but for\nthis they don't need the vtable symbol.)  Implicit constructors and destructors\nand explicit constructors already marked the vtable as used, but explicit\ndestructors didn't.\n\nNote that the only thing sema's \"mark a class's vtable used\" does is to mark all\nfinal overriders of the class as referenced, it does _not_ cause emission of\nthe vtable itself.  This is done on demand by codegen, independent of sema,\nsince sema might emit functions that are not referenced.  (The exception are\nvtables that are forced via key functions -- these are forced onto codegen\nby sema.)\n\nThis bug went unnoticed for years because it doesn't have observable effects\n(yet -- I want to change this in PR20337, which is why I noticed this).\n\nr213109 made it so that _calls_ to constructors don't mark the vtable used.\nCurrently, _calls_ to destructors still mark the vtable used.  If that\nwasn't the case, this program would tickle the problem:\n\n  test.h:\n    template <typename T>\n    struct B {\n      int* p;\n      virtual ~B() { delete p; }\n      virtual void f() {}\n    };\n\n    struct __attribute__((visibility(\"default\"))) C {\n      C();\n      B<int> m;\n    };\n\n  test2.cc:\n    #include \"test.h\"\n    int main() {\n      C* c = new C;\n      delete c;\n    }\n\n  test3.cc:\n    #include \"test.h\"\n    C::C() {}\n\n  # This bin/clang++ binary doesn't MarkVTableUsed() for virtual dtor calls:\n  $ bin/clang++ -shared test3.cc -std=c++11 -O2  -fvisibility=hidden \\\n        -fvisibility-inlines-hidden  -o libtest3.dylib\n  $ bin/clang++ test2.cc -std=c++11 -O2  -fvisibility=hidden \\\n        -fvisibility-inlines-hidden  libtest3.dylib\n  Undefined symbols for architecture x86_64:\n    \"B<int>::f()\", referenced from:\n        vtable for B<int> in test2-af8f4f.o\n  ld: symbol(s) not found for architecture x86_64\n\nWhat's happening here is that there's a copy of B's vtable hidden in\nlibtest3.dylib, because C's constructor caused an implicit instantiation of that\n(and implicit constructors generate vtables).\ntest2.cc calls C's destructDr, which destroys the B<int> member,\nwhich wants to overwrite the vtable back to B (think of B as the base of a class\nhierarchy, and of hierarchical destruction -- maybe we shouldn't do the vtable\nwriting in destructors of final classes), but there's nothing in test2.cc that\nmarks B's vtable used.  So codegen writes out the vtable, but since it wasn't\nmarked used, sema didn't mark all the virtual functions (in particular f())\nas used.\n\nNote that this change makes us reject programs we didn't reject before (see\nthe included Sema test case), but both gcc and cl also reject this code, and\nclang used to reject it before r213109.","distinct":true,"url":"https://api.github.com/repos/chapuni/llvm-project-submodule/commits/226ccdcbffaa1635f29d6a29699e7073332fe4e1"}]}