83 lines · cpp
1// RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fexceptions -o - | FileCheck %s2 3// PR41065: As background, when constructing a complete object, virtual bases4// are constructed first. If an exception is thrown while constructing a5// subobject later, those virtual bases are destroyed, so sema references the6// relevant constructors and destructors of every base class in case they are7// needed.8//9// However, an abstract class can never be used to construct a complete object.10// In the Itanium C++ ABI, this works out nicely, because we never end up11// emitting the "complete" constructor variant, only the "base" constructor12// variant, which can be called by constructors of derived classes. For various13// reasons, Sema does not mark ctors and dtors of virtual bases referenced when14// the constructor of an abstract class is emitted.15//16// In the Microsoft ABI, there are no complete/base variants, so before PR4106517// was fixed, the constructor of an abstract class could reference special18// members of a virtual base without marking them referenced. This could lead to19// unresolved symbol errors at link time.20//21// The fix is to implement the same optimization as Sema: If the class is22// abstract, don't bother initializing its virtual bases. The "is this class the23// most derived class" check in the constructor will never pass, and the virtual24// base constructor calls are always dead. Skip them.25 26struct A {27 A();28 virtual void f() = 0;29 virtual ~A();30};31 32// B has an implicit inline dtor, but is still abstract.33struct B : A {34 B(int n);35 int n;36};37 38// Still abstract39struct C : virtual B {40 C(int n);41 //void f() override;42};43 44// Not abstract, D::D calls C::C and B::B.45struct D : C {46 D(int n);47 void f() override;48};49 50void may_throw();51C::C(int n) : B(n) { may_throw(); }52 53// No branches, no constructor calls before may_throw();54//55// CHECK-LABEL: define dso_local noundef ptr @"??0C@@QEAA@H@Z"(ptr {{[^,]*}} returned align 8 dereferenceable(8) %this, i32 noundef %n, i32 noundef %is_most_derived)56// CHECK-NOT: br i157// CHECK-NOT: {{call.*@"\?0}}58// CHECK: call void @"?may_throw@@YAXXZ"()59// no cleanups60 61 62D::D(int n) : C(n), B(n) { may_throw(); }63 64// Conditionally construct (and destroy) vbase B, unconditionally C.65//66// CHECK-LABEL: define dso_local noundef ptr @"??0D@@QEAA@H@Z"(ptr {{[^,]*}} returned align 8 dereferenceable(8) %this, i32 noundef %n, i32 noundef %is_most_derived)67// CHECK: icmp ne i32 {{.*}}, 068// CHECK: br i169// CHECK: call noundef ptr @"??0B@@QEAA@H@Z"70// CHECK: br label71// CHECK: invoke noundef ptr @"??0C@@QEAA@H@Z"72// CHECK: invoke void @"?may_throw@@YAXXZ"()73// CHECK: cleanuppad74// CHECK: call void @"??1C@@UEAA@XZ"75// CHECK: cleanupret76//77// CHECK: cleanuppad78// CHECK: icmp ne i32 {{.*}}, 079// CHECK: br i180// CHECK: call void @"??1B@@UEAA@XZ"81// CHECK: br label82// CHECK: cleanupret83