1 // RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fexceptions -o - | FileCheck %s
3 // PR41065: As background, when constructing a complete object, virtual bases
4 // are constructed first. If an exception is thrown while constructing a
5 // subobject later, those virtual bases are destroyed, so sema references the
6 // relevant constructors and destructors of every base class in case they are
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 up
11 // emitting the "complete" constructor variant, only the "base" constructor
12 // variant, which can be called by constructors of derived classes. For various
13 // reasons, Sema does not mark ctors and dtors of virtual bases referenced when
14 // the constructor of an abstract class is emitted.
16 // In the Microsoft ABI, there are no complete/base variants, so before PR41065
17 // was fixed, the constructor of an abstract class could reference special
18 // members of a virtual base without marking them referenced. This could lead to
19 // unresolved symbol errors at link time.
21 // The fix is to implement the same optimization as Sema: If the class is
22 // abstract, don't bother initializing its virtual bases. The "is this class the
23 // most derived class" check in the constructor will never pass, and the virtual
24 // base constructor calls are always dead. Skip them.
32 // B has an implicit inline dtor, but is still abstract.
39 struct C
: virtual B
{
44 // Not abstract, D::D calls C::C and B::B.
51 C::C(int n
) : B(n
) { may_throw(); }
53 // No branches, no constructor calls before may_throw();
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)
57 // CHECK-NOT: {{call.*@"\?0}}
58 // CHECK: call void @"?may_throw@@YAXXZ"()
62 D::D(int n
) : C(n
), B(n
) { may_throw(); }
64 // Conditionally construct (and destroy) vbase B, unconditionally C.
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 {{.*}}, 0
69 // CHECK: call noundef ptr @"??0B@@QEAA@H@Z"
71 // CHECK: invoke noundef ptr @"??0C@@QEAA@H@Z"
72 // CHECK: invoke void @"?may_throw@@YAXXZ"()
74 // CHECK: call void @"??1C@@UEAA@XZ"
78 // CHECK: icmp ne i32 {{.*}}, 0
80 // CHECK: call void @"??1B@@UEAA@XZ"