Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
2 changes: 1 addition & 1 deletion clang/lib/CIR/CodeGen/CIRGenClass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -690,7 +690,7 @@ void CIRGenFunction::emitCXXAggrConstructorCall(
// every temporary created in a default argument expression is sequenced
// before the construction of the next array element, if any.
{
assert(!cir::MissingFeatures::runCleanupsScope());
RunCleanupsScope scope(*this);

// Evaluate the constructor and its arguments in a regular
// partial-destroy cleanup.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenCleanup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ using namespace clang::CIRGen;
// CIRGenFunction cleanup related
//===----------------------------------------------------------------------===//

/// Emits all the code to cause the given temporary to be cleaned up.
void CIRGenFunction::emitCXXTemporary(const CXXTemporary *temporary,
QualType tempType, Address ptr) {
pushDestroy(NormalAndEHCleanup, ptr, tempType, destroyCXXObject);
}

//===----------------------------------------------------------------------===//
// EHScopeStack
//===----------------------------------------------------------------------===//
Expand Down
30 changes: 24 additions & 6 deletions clang/lib/CIR/CodeGen/CIRGenExprAggregate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
return dest;
}

void ensureDest(mlir::Location loc, QualType ty) {
if (!dest.isIgnored())
return;
dest = cgf.createAggTemp(ty, loc, "agg.tmp.ensured");
}

public:
AggExprEmitter(CIRGenFunction &cgf, AggValueSlot dest)
: cgf(cgf), dest(dest) {}
Expand Down Expand Up @@ -96,10 +102,22 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
Visit(die->getExpr());
}
void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *e) {
assert(!cir::MissingFeatures::aggValueSlotDestructedFlag());
// Ensure that we have a slot, but if we already do, remember
// whether it was externally destructed.
bool wasExternallyDestructed = dest.isExternallyDestructed();
ensureDest(cgf.getLoc(e->getSourceRange()), e->getType());

// We're going to push a destructor if there isn't already one.
dest.setExternallyDestructed();

Visit(e->getSubExpr());

// Push that destructor we promised.
if (!wasExternallyDestructed)
cgf.emitCXXTemporary(e->getTemporary(), e->getType(), dest.getAddress());
}
void VisitLambdaExpr(LambdaExpr *e);
void VisitExprWithCleanups(ExprWithCleanups *e);

// Stubs -- These should be moved up when they are implemented.
void VisitCastExpr(CastExpr *e) {
Expand Down Expand Up @@ -239,11 +257,6 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXStdInitializerListExpr");
}

void VisitExprWithCleanups(ExprWithCleanups *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitExprWithCleanups");
}
void VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *e) {
cgf.cgm.errorNYI(e->getSourceRange(),
"AggExprEmitter: VisitCXXScalarValueInitExpr");
Expand Down Expand Up @@ -586,6 +599,11 @@ void AggExprEmitter::VisitLambdaExpr(LambdaExpr *e) {
}
}

void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *e) {
CIRGenFunction::RunCleanupsScope cleanups(cgf);
Visit(e->getSubExpr());
}

void AggExprEmitter::VisitCallExpr(const CallExpr *e) {
if (e->getCallReturnType(cgf.getContext())->isReferenceType()) {
cgf.cgm.errorNYI(e->getSourceRange(), "reference return type");
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
lexScope.forceCleanup();
b.create<cir::YieldOp>(loc, res);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
b.create<cir::YieldOp>(loc, res);
cir::YieldOp::create(b, loc, res);

},
/*falseBuilder*/
[&](mlir::OpBuilder &b, mlir::Location loc) {
Expand Down Expand Up @@ -1151,7 +1153,9 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
CIRGenFunction::LexicalScope lexScope{cgf, loc,
b.getInsertionBlock()};
cgf.curLexScope->setAsTernary();
b.create<cir::YieldOp>(loc, cgf.evaluateExprAsBool(e->getRHS()));
mlir::Value res = cgf.evaluateExprAsBool(e->getRHS());
lexScope.forceCleanup();
b.create<cir::YieldOp>(loc, res);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
b.create<cir::YieldOp>(loc, res);
cir::YieldOp::create(b, loc, res);

});

return maybePromoteBoolResult(resOp.getResult(), resTy);
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1240,6 +1240,9 @@ class CIRGenFunction : public CIRGenTypeCache {

RValue emitCXXPseudoDestructorExpr(const CXXPseudoDestructorExpr *expr);

void emitCXXTemporary(const CXXTemporary *temporary, QualType tempType,
Address ptr);

void emitCXXThrowExpr(const CXXThrowExpr *e);

void emitCtorPrologue(const clang::CXXConstructorDecl *ctor,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,13 @@ class AggValueSlot {
mayOverlap, isZeroed);
}

IsDestructed_t isExternallyDestructed() const {
return IsDestructed_t(destructedFlag);
}
void setExternallyDestructed(bool destructed = true) {
destructedFlag = destructed;
}

clang::Qualifiers getQualifiers() const { return quals; }

Address getAddress() const { return addr; }
Expand Down
173 changes: 173 additions & 0 deletions clang/test/CIR/CodeGen/dtors.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -std=c++20 -mconstructor-aliases -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG

struct A {
~A();
};

void test_temporary_dtor() {
A();
}

// CIR: cir.func dso_local @_Z19test_temporary_dtorv()
// CIR: %[[ALLOCA:.*]] = cir.alloca !rec_A, !cir.ptr<!rec_A>, ["agg.tmp0"]
// CIR: cir.call @_ZN1AD1Ev(%[[ALLOCA]]) nothrow : (!cir.ptr<!rec_A>) -> ()

// LLVM: define dso_local void @_Z19test_temporary_dtorv()
// LLVM: %[[ALLOCA:.*]] = alloca %struct.A, i64 1, align 1
// LLVM: call void @_ZN1AD1Ev(ptr %[[ALLOCA]])

// OGCG: define dso_local void @_Z19test_temporary_dtorv()
// OGCG: %[[ALLOCA:.*]] = alloca %struct.A, align 1
// OGCG: call void @_ZN1AD1Ev(ptr {{.*}} %[[ALLOCA]])

struct B {
int n;
B(int n) : n(n) {}
~B() {}
};

bool make_temp(const B &) { return false; }
bool test_temp_or() { return make_temp(1) || make_temp(2); }

// CIR: cir.func{{.*}} @_Z12test_temp_orv()
// CIR: %[[SCOPE:.*]] = cir.scope {
// CIR: %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"]
// CIR: %[[ONE:.*]] = cir.const #cir.int<1>
// CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]])
// CIR: %[[MAKE_TEMP0:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP0]])
// CIR: %[[TERNARY:.*]] = cir.ternary(%[[MAKE_TEMP0]], true {
// CIR: %[[TRUE:.*]] = cir.const #true
// CIR: cir.yield %[[TRUE]] : !cir.bool
// CIR: }, false {
// CIR: %[[REF_TMP1:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp1"]
// CIR: %[[TWO:.*]] = cir.const #cir.int<2>
// CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP1]], %[[TWO]])
// CIR: %[[MAKE_TEMP1:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP1]])
// CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP1]])
// CIR: cir.yield %[[MAKE_TEMP1]] : !cir.bool
// CIR: })
// CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP0]])
// CIR: cir.yield %[[TERNARY]] : !cir.bool
// CIR: } : !cir.bool

// LLVM: define{{.*}} i1 @_Z12test_temp_orv() {
// LLVM: %[[REF_TMP0:.*]] = alloca %struct.B
// LLVM: %[[REF_TMP1:.*]] = alloca %struct.B
// LLVM: br label %[[LOR_BEGIN:.*]]
// LLVM: [[LOR_BEGIN]]:
// LLVM: call void @_ZN1BC2Ei(ptr %[[REF_TMP0]], i32 1)
// LLVM: %[[MAKE_TEMP0:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP0]])
// LLVM: br i1 %[[MAKE_TEMP0]], label %[[LHS_TRUE_BLOCK:.*]], label %[[LHS_FALSE_BLOCK:.*]]
// LLVM: [[LHS_TRUE_BLOCK]]:
// LLVM: br label %[[RESULT_BLOCK:.*]]
// LLVM: [[LHS_FALSE_BLOCK]]:
// LLVM: call void @_ZN1BC2Ei(ptr %[[REF_TMP1]], i32 2)
// LLVM: %[[MAKE_TEMP1:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP1]])
// LLVM: call void @_ZN1BD2Ev(ptr %[[REF_TMP1]])
// LLVM: br label %[[RESULT_BLOCK]]
// LLVM: [[RESULT_BLOCK]]:
// LLVM: %[[RESULT:.*]] = phi i1 [ %[[MAKE_TEMP1]], %[[LHS_FALSE_BLOCK]] ], [ true, %[[LHS_TRUE_BLOCK]] ]
// LLVM: br label %[[LOR_END:.*]]
// LLVM: [[LOR_END]]:
// LLVM: call void @_ZN1BD2Ev(ptr %[[REF_TMP0]])

// OGCG: define {{.*}} i1 @_Z12test_temp_orv()
// OGCG: [[ENTRY:.*]]:
// OGCG: %[[RETVAL:.*]] = alloca i1
// OGCG: %[[REF_TMP0:.*]] = alloca %struct.B
// OGCG: %[[REF_TMP1:.*]] = alloca %struct.B
// OGCG: %[[CLEANUP_COND:.*]] = alloca i1
// OGCG: call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP0]], i32 {{.*}} 1)
// OGCG: %[[MAKE_TEMP0:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP0]])
// OGCG: store i1 false, ptr %cleanup.cond
// OGCG: br i1 %[[MAKE_TEMP0]], label %[[LOR_END:.*]], label %[[LOR_RHS:.*]]
// OGCG: [[LOR_RHS]]:
// OGCG: call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP1]], i32 {{.*}} 2)
// OGCG: store i1 true, ptr %[[CLEANUP_COND]]
// OGCG: %[[MAKE_TEMP1:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP1]])
// OGCG: br label %[[LOR_END]]
// OGCG: [[LOR_END]]:
// OGCG: %[[PHI:.*]] = phi i1 [ true, %[[ENTRY]] ], [ %[[MAKE_TEMP1]], %[[LOR_RHS]] ]
// OGCG: store i1 %[[PHI]], ptr %[[RETVAL]]
// OGCG: %[[CLEANUP_IS_ACTIVE:.*]] = load i1, ptr %[[CLEANUP_COND]]
// OGCG: br i1 %[[CLEANUP_IS_ACTIVE]], label %[[CLEANUP_ACTION:.*]], label %[[CLEANUP_DONE:.*]]
// OGCG: [[CLEANUP_ACTION]]:
// OGCG: call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP1]])
// OGCG: br label %[[CLEANUP_DONE]]
// OGCG: [[CLEANUP_DONE]]:
// OGCG: call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP0]])

bool test_temp_and() { return make_temp(1) && make_temp(2); }

// CIR: cir.func{{.*}} @_Z13test_temp_andv()
// CIR: %[[SCOPE:.*]] = cir.scope {
// CIR: %[[REF_TMP0:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp0"]
// CIR: %[[ONE:.*]] = cir.const #cir.int<1>
// CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP0]], %[[ONE]])
// CIR: %[[MAKE_TEMP0:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP0]])
// CIR: %[[TERNARY:.*]] = cir.ternary(%[[MAKE_TEMP0]], true {
// CIR: %[[REF_TMP1:.*]] = cir.alloca !rec_B, !cir.ptr<!rec_B>, ["ref.tmp1"]
// CIR: %[[TWO:.*]] = cir.const #cir.int<2>
// CIR: cir.call @_ZN1BC2Ei(%[[REF_TMP1]], %[[TWO]])
// CIR: %[[MAKE_TEMP1:.*]] = cir.call @_Z9make_tempRK1B(%[[REF_TMP1]])
// CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP1]])
// CIR: cir.yield %[[MAKE_TEMP1]] : !cir.bool
// CIR: }, false {
// CIR: %[[FALSE:.*]] = cir.const #false
// CIR: cir.yield %[[FALSE]] : !cir.bool
// CIR: })
// CIR: cir.call @_ZN1BD2Ev(%[[REF_TMP0]])
// CIR: cir.yield %[[TERNARY]] : !cir.bool
// CIR: } : !cir.bool

// LLVM: define{{.*}} i1 @_Z13test_temp_andv() {
// LLVM: %[[REF_TMP0:.*]] = alloca %struct.B
// LLVM: %[[REF_TMP1:.*]] = alloca %struct.B
// LLVM: br label %[[LAND_BEGIN:.*]]
// LLVM: [[LAND_BEGIN]]:
// LLVM: call void @_ZN1BC2Ei(ptr %[[REF_TMP0]], i32 1)
// LLVM: %[[MAKE_TEMP0:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP0]])
// LLVM: br i1 %[[MAKE_TEMP0]], label %[[LHS_TRUE_BLOCK:.*]], label %[[LHS_FALSE_BLOCK:.*]]
// LLVM: [[LHS_TRUE_BLOCK]]:
// LLVM: call void @_ZN1BC2Ei(ptr %[[REF_TMP1]], i32 2)
// LLVM: %[[MAKE_TEMP1:.*]] = call i1 @_Z9make_tempRK1B(ptr %[[REF_TMP1]])
// LLVM: call void @_ZN1BD2Ev(ptr %[[REF_TMP1]])
// LLVM: br label %[[RESULT_BLOCK:.*]]
// LLVM: [[LHS_FALSE_BLOCK]]:
// LLVM: br label %[[RESULT_BLOCK]]
// LLVM: [[RESULT_BLOCK]]:
// LLVM: %[[RESULT:.*]] = phi i1 [ false, %[[LHS_FALSE_BLOCK]] ], [ %[[MAKE_TEMP1]], %[[LHS_TRUE_BLOCK]] ]
// LLVM: br label %[[LAND_END:.*]]
// LLVM: [[LAND_END]]:
// LLVM: call void @_ZN1BD2Ev(ptr %[[REF_TMP0]])

// OGCG: define {{.*}} i1 @_Z13test_temp_andv()
// OGCG: [[ENTRY:.*]]:
// OGCG: %[[RETVAL:.*]] = alloca i1
// OGCG: %[[REF_TMP0:.*]] = alloca %struct.B
// OGCG: %[[REF_TMP1:.*]] = alloca %struct.B
// OGCG: %[[CLEANUP_COND:.*]] = alloca i1
// OGCG: call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP0]], i32 {{.*}} 1)
// OGCG: %[[MAKE_TEMP0:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP0]])
// OGCG: store i1 false, ptr %cleanup.cond
// OGCG: br i1 %[[MAKE_TEMP0]], label %[[LAND_RHS:.*]], label %[[LAND_END:.*]]
// OGCG: [[LAND_RHS]]:
// OGCG: call void @_ZN1BC2Ei(ptr {{.*}} %[[REF_TMP1]], i32 {{.*}} 2)
// OGCG: store i1 true, ptr %[[CLEANUP_COND]]
// OGCG: %[[MAKE_TEMP1:.*]] = call {{.*}} i1 @_Z9make_tempRK1B(ptr {{.*}} %[[REF_TMP1]])
// OGCG: br label %[[LAND_END]]
// OGCG: [[LAND_END]]:
// OGCG: %[[PHI:.*]] = phi i1 [ false, %[[ENTRY]] ], [ %[[MAKE_TEMP1]], %[[LAND_RHS]] ]
// OGCG: store i1 %[[PHI]], ptr %[[RETVAL]]
// OGCG: %[[CLEANUP_IS_ACTIVE:.*]] = load i1, ptr %[[CLEANUP_COND]]
// OGCG: br i1 %[[CLEANUP_IS_ACTIVE]], label %[[CLEANUP_ACTION:.*]], label %[[CLEANUP_DONE:.*]]
// OGCG: [[CLEANUP_ACTION]]:
// OGCG: call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP1]])
// OGCG: br label %[[CLEANUP_DONE]]
// OGCG: [[CLEANUP_DONE]]:
// OGCG: call void @_ZN1BD2Ev(ptr {{.*}} %[[REF_TMP0]])