Skip to content

Commit 18ad5b8

Browse files
authored
[CIR][CIRGen] Support a defined pure virtual destructor (#825)
This is permitted by the language, and IRGen emits traps for destructors other than the base object destructor. Make CIRGen follow suit.
1 parent fcc2590 commit 18ad5b8

File tree

2 files changed

+66
-1
lines changed

2 files changed

+66
-1
lines changed

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1109,7 +1109,14 @@ void CIRGenFunction::buildDestructorBody(FunctionArgList &Args) {
11091109
// in fact emit references to them from other compilations, so emit them
11101110
// as functions containing a trap instruction.
11111111
if (DtorType != Dtor_Base && Dtor->getParent()->isAbstract()) {
1112-
llvm_unreachable("NYI");
1112+
SourceLocation Loc =
1113+
Dtor->hasBody() ? Dtor->getBody()->getBeginLoc() : Dtor->getLocation();
1114+
builder.create<mlir::cir::TrapOp>(getLoc(Loc));
1115+
// The corresponding clang/CodeGen logic clears the insertion point here,
1116+
// but MLIR's builder requires a valid insertion point, so we create a dummy
1117+
// block (since the trap is a block terminator).
1118+
builder.createBlock(builder.getBlock()->getParent());
1119+
return;
11131120
}
11141121

11151122
Stmt *Body = Dtor->getBody();
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --input-file=%t.cir %s
3+
4+
// Pure virtual functions are allowed to be defined, but the vtable should still
5+
// point to __cxa_pure_virtual instead of the definition. For destructors, the
6+
// base object destructor (which is not included in the vtable) should be
7+
// defined as usual. The complete object destructors and deleting destructors
8+
// should contain a trap, and the vtable entries for them should point to
9+
// __cxa_pure_virtual.
10+
class C {
11+
C();
12+
virtual ~C() = 0;
13+
virtual void pure() = 0;
14+
};
15+
16+
C::C() = default;
17+
C::~C() = default;
18+
void C::pure() {}
19+
20+
// CHECK: @_ZTV1C = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1C> : !cir.ptr<!u8i>
21+
// complete object destructor (D1)
22+
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>,
23+
// deleting destructor (D0)
24+
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>,
25+
// C::pure
26+
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>]>
27+
28+
// The base object destructor should be emitted as normal.
29+
// CHECK-LABEL: cir.func @_ZN1CD2Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
30+
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
31+
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
32+
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
33+
// CHECK-NEXT: cir.return
34+
// CHECK-NEXT: }
35+
36+
// The complete object destructor should trap.
37+
// CHECK-LABEL: cir.func @_ZN1CD1Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
38+
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
39+
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
40+
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
41+
// CHECK-NEXT: cir.trap
42+
// CHECK-NEXT: }
43+
44+
// The deleting destructor should trap.
45+
// CHECK-LABEL: cir.func @_ZN1CD0Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
46+
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
47+
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
48+
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
49+
// CHECK-NEXT: cir.trap
50+
// CHECK-NEXT: }
51+
52+
// C::pure should be emitted as normal.
53+
// CHECK-LABEL: cir.func @_ZN1C4pureEv(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
54+
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
55+
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
56+
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
57+
// CHECK-NEXT: cir.return
58+
// CHECK-NEXT: }

0 commit comments

Comments
 (0)