Clang Project

clang_source_code/test/CodeGenCXX/msabi-ctor-abstract-vbase.cpp
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
26struct A {
27  A();
28  virtual void f() = 0;
29  virtual ~A();
30};
31
32// B has an implicit inline dtor, but is still abstract.
33struct B : A {
34  B(int n);
35  int n;
36};
37
38// Still abstract
39struct C : virtual B {
40  C(int n);
41  //void f() override;
42};
43
44// Not abstract, D::D calls C::C and B::B.
45struct D : C {
46  D(int n);
47  void f() override;
48};
49
50void may_throw();
51C::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
62D::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