1 // RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fexceptions -o - | FileCheck %s 2 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 7 // 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 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. 15 // 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. 20 // 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. 25 26 struct A { 27 A(); 28 virtual void f() = 0; 29 virtual ~A(); 30 }; 31 32 // B has an implicit inline dtor, but is still abstract. 33 struct B : A { 34 B(int n); 35 int n; 36 }; 37 38 // Still abstract 39 struct C : virtual B { 40 C(int n); 41 //void f() override; 42 }; 43 44 // Not abstract, D::D calls C::C and B::B. 45 struct D : C { 46 D(int n); 47 void f() override; 48 }; 49 50 void may_throw(); 51 C::C(int n) : B(n) { may_throw(); } 52 53 // No branches, no constructor calls before may_throw(); 54 // 55 // CHECK-LABEL: define dso_local %struct.C* @"??0C@@QEAA@H@Z"(%struct.C* {{[^,]*}} returned {{[^,]*}} %this, i32 %n, i32 %is_most_derived) 56 // CHECK-NOT: br i1 57 // CHECK-NOT: {{call.*@"\?0}} 58 // CHECK: call void @"?may_throw@@YAXXZ"() 59 // no cleanups 60 61 62 D::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 %struct.D* @"??0D@@QEAA@H@Z"(%struct.D* {{[^,]*}} returned {{[^,]*}} %this, i32 %n, i32 %is_most_derived) 67 // CHECK: icmp ne i32 {{.*}}, 0 68 // CHECK: br i1 69 // CHECK: call %struct.B* @"??0B@@QEAA@H@Z" 70 // CHECK: br label 71 // CHECK: invoke %struct.C* @"??0C@@QEAA@H@Z" 72 // CHECK: invoke void @"?may_throw@@YAXXZ"() 73 // CHECK: cleanuppad 74 // CHECK: call void @"??1C@@UEAA@XZ" 75 // CHECK: cleanupret 76 // 77 // CHECK: cleanuppad 78 // CHECK: icmp ne i32 {{.*}}, 0 79 // CHECK: br i1 80 // CHECK: call void @"??1B@@UEAA@XZ" 81 // CHECK: br label 82 // CHECK: cleanupret 83