Skip to content

[CIR][CodeGen] Implemented CIR generation for CXXPseudoDestructorExpr #1753

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 28, 2025
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
18 changes: 15 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenCall.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class CIRGenCallee {
enum class SpecialKind : uintptr_t {
Invalid,
Builtin,
PsuedoDestructor,
PseudoDestructor,
Virtual,

Last = Virtual
Expand Down Expand Up @@ -128,8 +128,20 @@ class CIRGenCallee {
return result;
}

bool isPsuedoDestructor() const {
return KindOrFunctionPointer == SpecialKind::PsuedoDestructor;
static CIRGenCallee
forPseudoDestructor(const clang::CXXPseudoDestructorExpr *expr) {
CIRGenCallee result(SpecialKind::PseudoDestructor);
result.PseudoDestructorInfo.Expr = expr;
return result;
}

bool isPseudoDestructor() const {
return KindOrFunctionPointer == SpecialKind::PseudoDestructor;
}

const CXXPseudoDestructorExpr *getPseudoDestructorExpr() const {
assert(isPseudoDestructor());
return PseudoDestructorInfo.Expr;
}

bool isOrdinary() const {
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -576,10 +576,11 @@ CIRGenCallee CIRGenFunction::emitCallee(const clang::Expr *E) {
emitIgnoredExpr(ME->getBase());
return emitDirectCallee(CGM, FD);
}
} else if (auto *PDE = dyn_cast<CXXPseudoDestructorExpr>(E)) {
return CIRGenCallee::forPseudoDestructor(PDE);
}

assert(!dyn_cast<SubstNonTypeTemplateParmExpr>(E) && "NYI");
assert(!dyn_cast<CXXPseudoDestructorExpr>(E) && "NYI");

// Otherwise, we have an indirect reference.
mlir::Value calleePtr;
Expand Down Expand Up @@ -1420,7 +1421,8 @@ RValue CIRGenFunction::emitCallExpr(const clang::CallExpr *E,
return emitBuiltinExpr(callee.getBuiltinDecl(), callee.getBuiltinID(), E,
ReturnValue);

assert(!callee.isPsuedoDestructor() && "NYI");
if (callee.isPseudoDestructor())
return emitCXXPseudoDestructorExpr(callee.getPseudoDestructorExpr());

return emitCall(E->getCallee()->getType(), callee, E, ReturnValue);
}
Expand Down
49 changes: 49 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1578,6 +1578,55 @@ RValue CIRGenFunction::emitCXXDestructorCall(GlobalDecl Dtor,
: getLoc(Dtor.getDecl()->getSourceRange()));
}

RValue CIRGenFunction::emitCXXPseudoDestructorExpr(
const CXXPseudoDestructorExpr *expr) {
QualType destroyedType = expr->getDestroyedType();
if (destroyedType.hasStrongOrWeakObjCLifetime()) {
// Automatic Reference Counting:
// If the pseudo-expression names a retainable object with weak or
// strong lifetime, the object shall be released.
Expr *baseExpr = expr->getBase();
Address baseValue = Address::invalid();
Qualifiers baseQuals;

// If this is s.x, emit s as an lvalue. If it is s->x, emit s as a scalar.
if (expr->isArrow()) {
baseValue = emitPointerWithAlignment(baseExpr);
const auto *ptrTy = baseExpr->getType()->castAs<PointerType>();
baseQuals = ptrTy->getPointeeType().getQualifiers();
} else {
LValue baseLV = emitLValue(baseExpr);
baseValue = baseLV.getAddress();
QualType baseTy = baseExpr->getType();
baseQuals = baseTy.getQualifiers();
}

switch (destroyedType.getObjCLifetime()) {
case Qualifiers::OCL_None:
case Qualifiers::OCL_ExplicitNone:
case Qualifiers::OCL_Autoreleasing:
break;

case Qualifiers::OCL_Strong:
llvm_unreachable("NYI, emitArcRelease");
break;

case Qualifiers::OCL_Weak:
llvm_unreachable("NYI, emitARCDestroyWeak");
break;
}
} else {
// C++ [expr.pseudo]p1:
// The result shall only be used as the operand for the function call
// operator (), and the result of such a call has type void. The only
// effect is the evaluation of the postfix-expression before the dot or
// arrow.
emitIgnoredExpr(expr->getBase());
}

return RValue::get(nullptr);
}

/// Emit a call to an operator new or operator delete function, as implicitly
/// created by new-expressions and delete-expressions.
static RValue emitNewDeleteCall(CIRGenFunction &CGF,
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -2060,6 +2060,8 @@ class CIRGenFunction : public CIRGenTypeCache {
const CXXMethodDecl *MD,
ReturnValueSlot ReturnValue);

RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);

void emitCXXTemporary(const CXXTemporary *Temporary, QualType TempType,
Address Ptr);

Expand Down
11 changes: 11 additions & 0 deletions clang/test/CIR/CodeGen/dtors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,17 @@ bool bar2() { return foo(1) && foo(2); }
// CHECK: }) : (!cir.bool) -> !cir.bool
// CHECK: cir.call @_ZN1XD2Ev

typedef int I;
void pseudo_dtor() {
I x = 10;
x.I::~I();
}
// CHECK: cir.func dso_local @_Z11pseudo_dtorv()
// CHECK: %[[INT:.*]] = cir.alloca !s32i, !cir.ptr<!s32i>
// CHECK: %[[TEN:.*]] = cir.const #cir.int<10> : !s32i
// CHECK: cir.store{{.*}} %[[TEN]], %[[INT]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.return

// @B::~B() #1 definition call into base @A::~A()
// CHECK: cir.func linkonce_odr @_ZN1BD2Ev{{.*}}{
// CHECK: cir.call @_ZN1AD2Ev(
Expand Down
Loading