[clang] Handle __declspec() attributes in using
[llvm-project.git] / clang / test / CodeGenCXX / msabi-ctor-abstract-vbase.cpp
blob71aea616f5d8e5f1e1a9d966a87ab6a3781f8072
1 // RUN: %clang_cc1 -triple x86_64-windows-msvc %s -emit-llvm -fexceptions -o - | FileCheck %s
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.
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.
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.
26 struct A {
27 A();
28 virtual void f() = 0;
29 virtual ~A();
32 // B has an implicit inline dtor, but is still abstract.
33 struct B : A {
34 B(int n);
35 int n;
38 // Still abstract
39 struct C : virtual B {
40 C(int n);
41 //void f() override;
44 // Not abstract, D::D calls C::C and B::B.
45 struct D : C {
46 D(int n);
47 void f() override;
50 void may_throw();
51 C::C(int n) : B(n) { may_throw(); }
53 // No branches, no constructor calls before may_throw();
55 // CHECK-LABEL: define dso_local noundef ptr @"??0C@@QEAA@H@Z"(ptr {{[^,]*}} returned align 8 dereferenceable(8) %this, i32 noundef %n, i32 noundef %is_most_derived)
56 // CHECK-NOT: br i1
57 // CHECK-NOT: {{call.*@"\?0}}
58 // CHECK: call void @"?may_throw@@YAXXZ"()
59 // no cleanups
62 D::D(int n) : C(n), B(n) { may_throw(); }
64 // Conditionally construct (and destroy) vbase B, unconditionally C.
66 // CHECK-LABEL: define dso_local noundef ptr @"??0D@@QEAA@H@Z"(ptr {{[^,]*}} returned align 8 dereferenceable(8) %this, i32 noundef %n, i32 noundef %is_most_derived)
67 // CHECK: icmp ne i32 {{.*}}, 0
68 // CHECK: br i1
69 // CHECK: call noundef ptr @"??0B@@QEAA@H@Z"
70 // CHECK: br label
71 // CHECK: invoke noundef ptr @"??0C@@QEAA@H@Z"
72 // CHECK: invoke void @"?may_throw@@YAXXZ"()
73 // CHECK: cleanuppad
74 // CHECK: call void @"??1C@@UEAA@XZ"
75 // CHECK: cleanupret
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