// RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fexceptions -o - | FileCheck %s // PR41065: As background, when constructing a complete object, virtual bases // are constructed first. If an exception is thrown while constructing a // subobject later, those virtual bases are destroyed, so sema references the // relevant constructors and destructors of every base class in case they are // needed. // // However, an abstract class can never be used to construct a complete object. // In the Itanium C++ ABI, this works out nicely, because we never end up // emitting the "complete" constructor variant, only the "base" constructor // variant, which can be called by constructors of derived classes. For various // reasons, Sema does not mark ctors and dtors of virtual bases referenced when // the constructor of an abstract class is emitted. // // In the Microsoft ABI, there are no complete/base variants, so before PR41065 // was fixed, the constructor of an abstract class could reference special // members of a virtual base without marking them referenced. This could lead to // unresolved symbol errors at link time. // // The fix is to implement the same optimization as Sema: If the class is // abstract, don't bother initializing its virtual bases. The "is this class the // most derived class" check in the constructor will never pass, and the virtual // base constructor calls are always dead. Skip them. struct A { A(); virtual void f() = 0; virtual ~A(); }; // B has an implicit inline dtor, but is still abstract. struct B : A { B(int n); int n; }; // Still abstract struct C : virtual B { C(int n); //void f() override; }; // Not abstract, D::D calls C::C and B::B. struct D : C { D(int n); void f() override; }; void may_throw(); C::C(int n) : B(n) { may_throw(); } // No branches, no constructor calls before may_throw(); // // CHECK-LABEL: define dso_local %struct.C* @"??0C@@QEAA@H@Z"(%struct.C* returned %this, i32 %n, i32 %is_most_derived) // CHECK-NOT: br i1 // CHECK-NOT: {{call.*@"\?0}} // CHECK: call void @"?may_throw@@YAXXZ"() // no cleanups D::D(int n) : C(n), B(n) { may_throw(); } // Conditionally construct (and destroy) vbase B, unconditionally C. // // CHECK-LABEL: define dso_local %struct.D* @"??0D@@QEAA@H@Z"(%struct.D* returned %this, i32 %n, i32 %is_most_derived) // CHECK: icmp ne i32 {{.*}}, 0 // CHECK: br i1 // CHECK: call %struct.B* @"??0B@@QEAA@H@Z" // CHECK: br label // CHECK: invoke %struct.C* @"??0C@@QEAA@H@Z" // CHECK: invoke void @"?may_throw@@YAXXZ"() // CHECK: cleanuppad // CHECK: call void @"??1C@@UEAA@XZ" // CHECK: cleanupret // // CHECK: cleanuppad // CHECK: icmp ne i32 {{.*}}, 0 // CHECK: br i1 // CHECK: call void @"??1B@@UEAA@XZ" // CHECK: br label // CHECK: cleanupret