Skip to content

Commit aa282a9

Browse files
committed
[CIR][CIRGen] Handle paren list init and get dtors right
1 parent 27849d7 commit aa282a9

File tree

6 files changed

+118
-4
lines changed

6 files changed

+118
-4
lines changed

clang/include/clang/CIR/MissingFeatures.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ struct MissingFeatures {
184184
static bool deferredReplacements() { return false; }
185185
static bool shouldInstrumentFunction() { return false; }
186186
static bool xray() { return false; }
187+
static bool flagLoad() { return false; }
187188

188189
// Inline assembly
189190
static bool asmGoto() { return false; }

clang/lib/CIR/CodeGen/CIRGenClass.cpp

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1236,6 +1236,30 @@ struct CallDtorDelete final : EHScopeStack::Cleanup {
12361236
};
12371237
} // namespace
12381238

1239+
class DestroyField final : public EHScopeStack::Cleanup {
1240+
const FieldDecl *field;
1241+
CIRGenFunction::Destroyer *destroyer;
1242+
bool useEHCleanupForArray;
1243+
1244+
public:
1245+
DestroyField(const FieldDecl *field, CIRGenFunction::Destroyer *destroyer,
1246+
bool useEHCleanupForArray)
1247+
: field(field), destroyer(destroyer),
1248+
useEHCleanupForArray(useEHCleanupForArray) {}
1249+
1250+
void Emit(CIRGenFunction &CGF, Flags flags) override {
1251+
// Find the address of the field.
1252+
Address thisValue = CGF.LoadCXXThisAddress();
1253+
QualType RecordTy = CGF.getContext().getTagDeclType(field->getParent());
1254+
LValue ThisLV = CGF.makeAddrLValue(thisValue, RecordTy);
1255+
LValue LV = CGF.buildLValueForField(ThisLV, field);
1256+
assert(LV.isSimple());
1257+
1258+
CGF.emitDestroy(LV.getAddress(), field->getType(), destroyer,
1259+
flags.isForNormalCleanup() && useEHCleanupForArray);
1260+
}
1261+
};
1262+
12391263
/// Emit all code that comes at the end of class's destructor. This is to call
12401264
/// destructors on members and base classes in reverse order of their
12411265
/// construction.
@@ -1346,8 +1370,9 @@ void CIRGenFunction::EnterDtorCleanups(const CXXDestructorDecl *DD,
13461370
if (RT && RT->getDecl()->isAnonymousStructOrUnion())
13471371
continue;
13481372

1349-
[[maybe_unused]] CleanupKind cleanupKind = getCleanupKind(dtorKind);
1350-
llvm_unreachable("EHStack.pushCleanup<DestroyField>(...) NYI");
1373+
CleanupKind cleanupKind = getCleanupKind(dtorKind);
1374+
EHStack.pushCleanup<DestroyField>(
1375+
cleanupKind, Field, getDestroyer(dtorKind), cleanupKind & EHCleanup);
13511376
}
13521377

13531378
if (SanitizeFields)

clang/lib/CIR/CodeGen/CIRGenDecl.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,3 +1247,22 @@ void CIRGenFunction::pushEHDestroy(QualType::DestructionKind dtorKind,
12471247

12481248
pushDestroy(EHCleanup, addr, type, getDestroyer(dtorKind), true);
12491249
}
1250+
1251+
// Pushes a destroy and defers its deactivation until its
1252+
// CleanupDeactivationScope is exited.
1253+
void CIRGenFunction::pushDestroyAndDeferDeactivation(
1254+
QualType::DestructionKind dtorKind, Address addr, QualType type) {
1255+
assert(dtorKind && "cannot push destructor for trivial type");
1256+
1257+
CleanupKind cleanupKind = getCleanupKind(dtorKind);
1258+
pushDestroyAndDeferDeactivation(
1259+
cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
1260+
}
1261+
1262+
void CIRGenFunction::pushDestroyAndDeferDeactivation(
1263+
CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
1264+
bool useEHCleanupForArray) {
1265+
assert(!MissingFeatures::flagLoad());
1266+
pushDestroy(cleanupKind, addr, type, destroyer, useEHCleanupForArray);
1267+
DeferredDeactivationCleanupStack.push_back({EHStack.stable_begin(), nullptr});
1268+
}

clang/lib/CIR/CodeGen/CIRGenExprAgg.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ class AggExprEmitter : public StmtVisitor<AggExprEmitter> {
274274
void VisitAbstractConditionalOperator(const AbstractConditionalOperator *E);
275275
void VisitChooseExpr(const ChooseExpr *E) { llvm_unreachable("NYI"); }
276276
void VisitInitListExpr(InitListExpr *E);
277+
void VisitCXXParenListInitExpr(CXXParenListInitExpr *E);
277278
void VisitCXXParenListOrInitListExpr(Expr *ExprToVisit, ArrayRef<Expr *> Args,
278279
FieldDecl *InitializedFieldInUnion,
279280
Expr *ArrayFiller);
@@ -1194,6 +1195,12 @@ void AggExprEmitter::VisitBinCmp(const BinaryOperator *E) {
11941195
// All done! The result is in the Dest slot.
11951196
}
11961197

1198+
void AggExprEmitter::VisitCXXParenListInitExpr(CXXParenListInitExpr *E) {
1199+
VisitCXXParenListOrInitListExpr(E, E->getInitExprs(),
1200+
E->getInitializedFieldInUnion(),
1201+
E->getArrayFiller());
1202+
}
1203+
11971204
void AggExprEmitter::VisitInitListExpr(InitListExpr *E) {
11981205
// TODO(cir): use something like CGF.ErrorUnsupported
11991206
if (E->hadArrayRangeDesignator())
@@ -1350,10 +1357,14 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
13501357
// Push a destructor if necessary.
13511358
// FIXME: if we have an array of structures, all explicitly
13521359
// initialized, we can end up pushing a linear number of cleanups.
1353-
[[maybe_unused]] bool pushedCleanup = false;
13541360
if (QualType::DestructionKind dtorKind =
13551361
field->getType().isDestructedType()) {
1356-
llvm_unreachable("NYI");
1362+
assert(LV.isSimple());
1363+
if (dtorKind) {
1364+
CGF.pushDestroyAndDeferDeactivation(NormalAndEHCleanup, LV.getAddress(),
1365+
field->getType(),
1366+
CGF.getDestroyer(dtorKind), false);
1367+
}
13571368
}
13581369

13591370
// From LLVM codegen, maybe not useful for CIR:

clang/lib/CIR/CodeGen/CIRGenFunction.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,20 @@ class CIRGenFunction : public CIRGenTypeCache {
375375
EHScopeStack EHStack;
376376
llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
377377

378+
// A stack of cleanups which were added to EHStack but have to be deactivated
379+
// later before being popped or emitted. These are usually deactivated on
380+
// exiting a `CleanupDeactivationScope` scope. For instance, after a
381+
// full-expr.
382+
//
383+
// These are specially useful for correctly emitting cleanups while
384+
// encountering branches out of expression (through stmt-expr or coroutine
385+
// suspensions).
386+
struct DeferredDeactivateCleanup {
387+
EHScopeStack::stable_iterator Cleanup;
388+
mlir::Operation *DominatingIP;
389+
};
390+
llvm::SmallVector<DeferredDeactivateCleanup> DeferredDeactivationCleanupStack;
391+
378392
/// A mapping from NRVO variables to the flags used to indicate
379393
/// when the NRVO has been applied to this variable.
380394
llvm::DenseMap<const VarDecl *, mlir::Value> NRVOFlags;
@@ -1811,6 +1825,11 @@ class CIRGenFunction : public CIRGenTypeCache {
18111825
QualType elementType,
18121826
CharUnits elementAlign,
18131827
Destroyer *destroyer);
1828+
void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind,
1829+
Address addr, QualType type);
1830+
void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr,
1831+
QualType type, Destroyer *destroyer,
1832+
bool useEHCleanupForArray);
18141833
void buildArrayDestroy(mlir::Value begin, mlir::Value end,
18151834
QualType elementType, CharUnits elementAlign,
18161835
Destroyer *destroyer, bool checkZeroLength,
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// RUN: %clang_cc1 -std=c++20 -triple aarch64-none-linux-android21 -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
2+
// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s
3+
4+
struct Vec {
5+
Vec();
6+
Vec(Vec&&);
7+
~Vec();
8+
};
9+
10+
struct S1 {
11+
Vec v;
12+
};
13+
14+
// CIR-DAG: ![[VecType:.*]] = !cir.struct<struct "Vec" {!cir.int<u, 8>}>
15+
// CIR-DAG: ![[S1:.*]] = !cir.struct<struct "S1" {!cir.struct<struct "Vec" {!cir.int<u, 8>}>}>
16+
17+
template <int I>
18+
void make1() {
19+
Vec v;
20+
S1((Vec&&) v);
21+
// CIR: cir.func linkonce_odr @_Z5make1ILi0EEvv()
22+
// CIR: %[[VEC:.*]] = cir.alloca ![[VecType]], !cir.ptr<![[VecType]]>
23+
// CIR: cir.call @_ZN3VecC1Ev(%[[VEC]]) : (!cir.ptr<![[VecType]]>)
24+
// CIR: cir.scope {
25+
// CIR: %[[AGG_TMP:.*]] = cir.alloca ![[S1]], !cir.ptr<![[S1]]>, ["agg.tmp.ensured"]
26+
// CIR: %[[FIELD:.*]] = cir.get_member %[[AGG_TMP]][0] {name = "v"} : !cir.ptr<![[S1]]> -> !cir.ptr<![[VecType]]>
27+
// CIR: cir.call @_ZN3VecC1EOS_(%[[FIELD]], %[[VEC]]) : (!cir.ptr<![[VecType]]>, !cir.ptr<![[VecType]]>) -> ()
28+
// CIR: cir.call @_ZN2S1D1Ev(%[[AGG_TMP]]) : (!cir.ptr<![[S1]]>) -> ()
29+
// CIR: cir.call @_ZN3VecD1Ev(%[[FIELD]]) : (!cir.ptr<![[VecType]]>) -> ()
30+
// CIR: }
31+
32+
// FIXME: implement MissingFeatures::flagLoad(), do not emit this a second time.
33+
// CIR: cir.call @_ZN3VecD1Ev(%[[VEC]]) : (!cir.ptr<![[VecType]]>) -> ()
34+
// CIR: cir.return
35+
}
36+
37+
void foo() {
38+
make1<0>();
39+
}

0 commit comments

Comments
 (0)