Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,14 @@ void CIRGenFunction::buildDestructorBody(FunctionArgList &Args) {
// in fact emit references to them from other compilations, so emit them
// as functions containing a trap instruction.
if (DtorType != Dtor_Base && Dtor->getParent()->isAbstract()) {
llvm_unreachable("NYI");
SourceLocation Loc =
Dtor->hasBody() ? Dtor->getBody()->getBeginLoc() : Dtor->getLocation();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd make slightly more sense if the trap is has the getEndLoc instead.

builder.create<mlir::cir::TrapOp>(getLoc(Loc));
// The corresponding clang/CodeGen logic clears the insertion point here,
// but MLIR's builder requires a valid insertion point, so we create a dummy
// block (since the trap is a block terminator).
builder.createBlock(builder.getBlock()->getParent());
return;
}

Stmt *Body = Dtor->getBody();
Expand Down
58 changes: 58 additions & 0 deletions clang/test/CIR/CodeGen/defined-pure-virtual-func.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s

// Pure virtual functions are allowed to be defined, but the vtable should still
// point to __cxa_pure_virtual instead of the definition. For destructors, the
// base object destructor (which is not included in the vtable) should be
// defined as usual. The complete object destructors and deleting destructors
// should contain a trap, and the vtable entries for them should point to
// __cxa_pure_virtual.
class C {
C();
virtual ~C() = 0;
virtual void pure() = 0;
};

C::C() = default;
C::~C() = default;
void C::pure() {}

// CHECK: @_ZTV1C = #cir.vtable<{#cir.const_array<[#cir.ptr<null> : !cir.ptr<!u8i>, #cir.global_view<@_ZTI1C> : !cir.ptr<!u8i>
// complete object destructor (D1)
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>,
// deleting destructor (D0)
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>,
// C::pure
// CHECK-SAME: #cir.global_view<@__cxa_pure_virtual> : !cir.ptr<!u8i>]>

// The base object destructor should be emitted as normal.
// CHECK-LABEL: cir.func @_ZN1CD2Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, the tests should use regex for the SSA values, should make them a little more resistant to overall CIR changes.

// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
// CHECK-NEXT: cir.return
// CHECK-NEXT: }

// The complete object destructor should trap.
// CHECK-LABEL: cir.func @_ZN1CD1Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
// CHECK-NEXT: cir.trap
// CHECK-NEXT: }

// The deleting destructor should trap.
// CHECK-LABEL: cir.func @_ZN1CD0Ev(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
// CHECK-NEXT: cir.trap
// CHECK-NEXT: }

// C::pure should be emitted as normal.
// CHECK-LABEL: cir.func @_ZN1C4pureEv(%arg0: !cir.ptr<!ty_C> loc({{[^)]+}})) {{.*}} {
// CHECK-NEXT: %0 = cir.alloca !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>, ["this", init] {alignment = 8 : i64}
// CHECK-NEXT: cir.store %arg0, %0 : !cir.ptr<!ty_C>, !cir.ptr<!cir.ptr<!ty_C>>
// CHECK-NEXT: %1 = cir.load %0 : !cir.ptr<!cir.ptr<!ty_C>>, !cir.ptr<!ty_C>
// CHECK-NEXT: cir.return
// CHECK-NEXT: }