Reid Kleckner | 61c9b7c | 2019-03-18 22:41:50 +0000 | [diff] [blame] | 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 |