From 5e12002c6cea7601073888c2281525131caa77e3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Timm=20B=C3=A4der?= Date: Sun, 5 Mar 2023 13:18:13 +0100 Subject: [PATCH] Revert "[clang][Interp] Support destructors" This reverts commit 78e4237460bf58f3d6b75f275e0424f38e3b1d04. This breaks the memory sanitizer builder: https://lab.llvm.org/buildbot/#/builders/5/builds/31959 --- clang/lib/AST/Interp/ByteCodeExprGen.cpp | 78 +--------- clang/lib/AST/Interp/ByteCodeExprGen.h | 13 -- clang/lib/AST/Interp/ByteCodeStmtGen.cpp | 2 - clang/test/AST/Interp/cxx20.cpp | 247 ------------------------------- 4 files changed, 2 insertions(+), 338 deletions(-) diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 488d07e..bc682c9 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 DeclScope final : public VariableScope { +template class DeclScope final : public LocalScope { public: DeclScope(ByteCodeExprGen *Ctx, const ValueDecl *VD) - : VariableScope(Ctx), Scope(Ctx->P, VD) {} + : LocalScope(Ctx), Scope(Ctx->P, VD) {} void addExtended(const Scope::Local &Local) override { return this->addLocal(Local); @@ -1857,80 +1857,6 @@ void ByteCodeExprGen::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 -bool ByteCodeExprGen::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 differently 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 4d92927..231f39f 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -256,8 +256,6 @@ private: return FPO.getRoundingMode(); } - bool emitRecordDestruction(const Descriptor *Desc); - protected: /// Variable to storage mapping. llvm::DenseMap Locals; @@ -335,20 +333,9 @@ public: 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 547a24e..a4be86c 100644 --- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -428,7 +428,6 @@ bool ByteCodeStmtGen::visitBreakStmt(const BreakStmt *S) { if (!BreakLabel) return false; - this->emitCleanup(); return this->jump(*BreakLabel); } @@ -437,7 +436,6 @@ bool ByteCodeStmtGen::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 480d6e8..cc37722 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); -} -- 2.7.4