[clang] 5e12002 - Revert "[clang][Interp] Support destructors"
Timm Bäder via cfe-commits
cfe-commits at lists.llvm.org
Sun Mar 5 04:18:40 PST 2023
Author: Timm Bäder
Date: 2023-03-05T13:18:13+01:00
New Revision: 5e12002c6cea7601073888c2281525131caa77e3
URL: https://github.com/llvm/llvm-project/commit/5e12002c6cea7601073888c2281525131caa77e3
DIFF: https://github.com/llvm/llvm-project/commit/5e12002c6cea7601073888c2281525131caa77e3.diff
LOG: Revert "[clang][Interp] Support destructors"
This reverts commit 78e4237460bf58f3d6b75f275e0424f38e3b1d04.
This breaks the memory sanitizer builder:
https://lab.llvm.org/buildbot/#/builders/5/builds/31959
Added:
Modified:
clang/lib/AST/Interp/ByteCodeExprGen.cpp
clang/lib/AST/Interp/ByteCodeExprGen.h
clang/lib/AST/Interp/ByteCodeStmtGen.cpp
clang/test/AST/Interp/cxx20.cpp
Removed:
################################################################################
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index 488d07e09d9b5..bc682c92c143f 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -26,10 +26,10 @@ namespace clang {
namespace interp {
/// Scope used to handle temporaries in toplevel variable declarations.
-template <class Emitter> class DeclScope final : public VariableScope<Emitter> {
+template <class Emitter> class DeclScope final : public LocalScope<Emitter> {
public:
DeclScope(ByteCodeExprGen<Emitter> *Ctx, const ValueDecl *VD)
- : VariableScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
+ : LocalScope<Emitter>(Ctx), Scope(Ctx->P, VD) {}
void addExtended(const Scope::Local &Local) override {
return this->addLocal(Local);
@@ -1857,80 +1857,6 @@ void ByteCodeExprGen<Emitter>::emitCleanup() {
C->emitDestruction();
}
-/// When calling this, we have a pointer of the local-to-destroy
-/// on the stack.
-/// Emit destruction of record types (or arrays of record types).
-/// FIXME: Handle virtual destructors.
-template <class Emitter>
-bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Descriptor *Desc) {
- assert(Desc);
- assert(!Desc->isPrimitive());
- assert(!Desc->isPrimitiveArray());
-
- // Arrays.
- if (Desc->isArray()) {
- const Descriptor *ElemDesc = Desc->ElemDesc;
- const Record *ElemRecord = ElemDesc->ElemRecord;
- assert(ElemRecord); // This is not a primitive array.
-
- if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor();
- Dtor && !Dtor->isTrivial()) {
- for (ssize_t I = Desc->getNumElems() - 1; I >= 0; --I) {
- if (!this->emitConstUint64(I, SourceInfo{}))
- return false;
- if (!this->emitArrayElemPtrUint64(SourceInfo{}))
- return false;
- if (!this->emitRecordDestruction(Desc->ElemDesc))
- return false;
- }
- }
- return this->emitPopPtr(SourceInfo{});
- }
-
- const Record *R = Desc->ElemRecord;
- assert(R);
- // First, destroy all fields.
- for (const Record::Field &Field : llvm::reverse(R->fields())) {
- const Descriptor *D = Field.Desc;
- if (!D->isPrimitive() && !D->isPrimitiveArray()) {
- if (!this->emitDupPtr(SourceInfo{}))
- return false;
- if (!this->emitGetPtrField(Field.Offset, SourceInfo{}))
- return false;
- if (!this->emitRecordDestruction(D))
- return false;
- }
- }
-
- // FIXME: Unions need to be handled
diff erently here. We don't want to
- // call the destructor of its members.
-
- // Now emit the destructor and recurse into base classes.
- if (const CXXDestructorDecl *Dtor = R->getDestructor();
- Dtor && !Dtor->isTrivial()) {
- const Function *DtorFunc = getFunction(Dtor);
- if (DtorFunc && DtorFunc->isConstexpr()) {
- assert(DtorFunc->hasThisPointer());
- assert(DtorFunc->getNumParams() == 1);
- if (!this->emitDupPtr(SourceInfo{}))
- return false;
- if (!this->emitCall(DtorFunc, SourceInfo{}))
- return false;
- }
- }
-
- for (const Record::Base &Base : llvm::reverse(R->bases())) {
- if (!this->emitGetPtrBase(Base.Offset, SourceInfo{}))
- return false;
- if (!this->emitRecordDestruction(Base.Desc))
- return false;
- }
- // FIXME: Virtual bases.
-
- // Remove the instance pointer.
- return this->emitPopPtr(SourceInfo{});
-}
-
namespace clang {
namespace interp {
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h
index 4d929278f29c8..231f39ff8bd6d 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.h
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.h
@@ -256,8 +256,6 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
return FPO.getRoundingMode();
}
- bool emitRecordDestruction(const Descriptor *Desc);
-
protected:
/// Variable to storage mapping.
llvm::DenseMap<const ValueDecl *, Scope::Local> Locals;
@@ -335,20 +333,9 @@ template <class Emitter> class LocalScope : public VariableScope<Emitter> {
this->Ctx->Descriptors[*Idx].emplace_back(Local);
}
- /// Emit destruction of the local variable. This includes
- /// object destructors.
void emitDestruction() override {
if (!Idx)
return;
- // Emit destructor calls for local variables of record
- // type with a destructor.
- for (Scope::Local &Local : this->Ctx->Descriptors[*Idx]) {
- if (!Local.Desc->isPrimitive() && !Local.Desc->isPrimitiveArray()) {
- this->Ctx->emitGetPtrLocal(Local.Offset, SourceInfo{});
- this->Ctx->emitRecordDestruction(Local.Desc);
- }
- }
-
this->Ctx->emitDestroy(*Idx, SourceInfo{});
}
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 547a24e5b19d3..a4be86c0e0639 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -428,7 +428,6 @@ bool ByteCodeStmtGen<Emitter>::visitBreakStmt(const BreakStmt *S) {
if (!BreakLabel)
return false;
- this->emitCleanup();
return this->jump(*BreakLabel);
}
@@ -437,7 +436,6 @@ bool ByteCodeStmtGen<Emitter>::visitContinueStmt(const ContinueStmt *S) {
if (!ContinueLabel)
return false;
- this->emitCleanup();
return this->jump(*ContinueLabel);
}
diff --git a/clang/test/AST/Interp/cxx20.cpp b/clang/test/AST/Interp/cxx20.cpp
index 480d6e8e9a8a2..cc37722730fc2 100644
--- a/clang/test/AST/Interp/cxx20.cpp
+++ b/clang/test/AST/Interp/cxx20.cpp
@@ -271,250 +271,3 @@ namespace ConstThis {
// ref-error {{must have constant destruction}} \
// ref-note {{in call to}}
};
-
-namespace Destructors {
-
- class Inc final {
- public:
- int &I;
- constexpr Inc(int &I) : I(I) {}
- constexpr ~Inc() {
- I++;
- }
- };
-
- class Dec final {
- public:
- int &I;
- constexpr Dec(int &I) : I(I) {}
- constexpr ~Dec() {
- I--;
- }
- };
-
-
-
- constexpr int m() {
- int i = 0;
- {
- Inc f1(i);
- Inc f2(i);
- Inc f3(i);
- }
- return i;
- }
- static_assert(m() == 3, "");
-
-
- constexpr int C() {
- int i = 0;
-
- while (i < 10) {
- Inc inc(i);
- continue;
- Dec dec(i);
- }
- return i;
- }
- static_assert(C() == 10, "");
-
-
- constexpr int D() {
- int i = 0;
-
- {
- Inc i1(i);
- {
- Inc i2(i);
- return i;
- }
- }
-
- return i;
- }
- static_assert(D() == 0, "");
-
- constexpr int E() {
- int i = 0;
-
- for(;;) {
- Inc i1(i);
- break;
- }
- return i;
- }
- static_assert(E() == 1, "");
-
-
- /// FIXME: This should be rejected, since we call the destructor
- /// twice. However, GCC doesn't care either.
- constexpr int ManualDtor() {
- int i = 0;
- {
- Inc I(i); // ref-note {{destroying object 'I' whose lifetime has already ended}}
- I.~Inc();
- }
- return i;
- }
- static_assert(ManualDtor() == 1, ""); // expected-error {{static assertion failed}} \
- // expected-note {{evaluates to '2 == 1'}} \
- // ref-error {{not an integral constant expression}} \
- // ref-note {{in call to 'ManualDtor()'}}
-
- constexpr void doInc(int &i) {
- Inc I(i);
- return;
- }
- constexpr int testInc() {
- int i = 0;
- doInc(i);
- return i;
- }
- static_assert(testInc() == 1, "");
- constexpr void doInc2(int &i) {
- Inc I(i);
- // No return statement.
- }
- constexpr int testInc2() {
- int i = 0;
- doInc2(i);
- return i;
- }
- static_assert(testInc2() == 1, "");
-
-
- namespace DtorOrder {
- class A {
- public:
- int &I;
- constexpr A(int &I) : I(I) {}
- constexpr ~A() {
- I = 1337;
- }
- };
-
- class B : public A {
- public:
- constexpr B(int &I) : A(I) {}
- constexpr ~B() {
- I = 42;
- }
- };
-
- constexpr int foo() {
- int i = 0;
- {
- B b(i);
- }
- return i;
- }
-
- static_assert(foo() == 1337);
- }
-
- class FieldDtor1 {
- public:
- Inc I1;
- Inc I2;
- constexpr FieldDtor1(int &I) : I1(I), I2(I){}
- };
-
- constexpr int foo2() {
- int i = 0;
- {
- FieldDtor1 FD1(i);
- }
- return i;
- }
-
- static_assert(foo2() == 2);
-
- class FieldDtor2 {
- public:
- Inc Incs[3];
- constexpr FieldDtor2(int &I) : Incs{Inc(I), Inc(I), Inc(I)} {}
- };
-
- constexpr int foo3() {
- int i = 0;
- {
- FieldDtor2 FD2(i);
- }
- return i;
- }
-
- static_assert(foo3() == 3);
-
- struct ArrD {
- int index;
- int *arr;
- int &p;
- constexpr ~ArrD() {
- arr[p] = index;
- ++p;
- }
- };
- constexpr bool ArrayOrder() {
- int order[3] = {0, 0, 0};
- int p = 0;
- {
- ArrD ds[3] = {
- {1, order, p},
- {2, order, p},
- {3, order, p},
- };
- // ds will be destroyed.
- }
- return order[0] == 3 && order[1] == 2 && order[2] == 1;
- }
- static_assert(ArrayOrder());
-
-
- // Static members aren't destroyed.
- class Dec2 {
- public:
- int A = 0;
- constexpr ~Dec2() {
- A++;
- }
- };
- class Foo {
- public:
- static constexpr Dec2 a;
- static Dec2 b;
- };
- static_assert(Foo::a.A == 0);
- constexpr bool f() {
- Foo f;
- return true;
- }
- static_assert(Foo::a.A == 0);
- static_assert(f());
- static_assert(Foo::a.A == 0);
-
-
- struct NotConstexpr {
- NotConstexpr() {}
- ~NotConstexpr() {}
- };
-
- struct Outer {
- constexpr Outer() = default;
- constexpr ~Outer();
-
- constexpr int foo() {
- return 12;
- }
-
- constexpr int bar()const {
- return Outer{}.foo();
- }
-
- static NotConstexpr Val;
- };
-
- constexpr Outer::~Outer() {}
-
- constexpr Outer O;
- static_assert(O.bar() == 12);
-}
More information about the cfe-commits
mailing list