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();
C(int n)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 
D(int n)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