diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 6ad75d4e034a9..e8b0fffd5ee34 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -3365,45 +3365,8 @@ bool ByteCodeExprGen::emitComplexReal(const Expr *SubExpr) { return true; } -/// 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). template -bool ByteCodeExprGen::emitRecordDestruction(const Descriptor *Desc) { - assert(Desc); - assert(!Desc->isPrimitive()); - assert(!Desc->isPrimitiveArray()); - - // Arrays. - if (Desc->isArray()) { - const Descriptor *ElemDesc = Desc->ElemDesc; - assert(ElemDesc); - - // Don't need to do anything for these. - if (ElemDesc->isPrimitiveArray()) - return this->emitPopPtr(SourceInfo{}); - - // If this is an array of record types, check if we need - // to call the element destructors at all. If not, try - // to save the work. - if (const Record *ElemRecord = ElemDesc->ElemRecord) { - if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor(); - !Dtor || Dtor->isTrivial()) - return this->emitPopPtr(SourceInfo{}); - } - - 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(ElemDesc)) - return false; - } - return this->emitPopPtr(SourceInfo{}); - } - - const Record *R = Desc->ElemRecord; +bool ByteCodeExprGen::emitRecordDestruction(const Record *R) { assert(R); // First, destroy all fields. for (const Record::Field &Field : llvm::reverse(R->fields())) { @@ -3413,7 +3376,9 @@ bool ByteCodeExprGen::emitRecordDestruction(const Descriptor *Desc) { return false; if (!this->emitGetPtrField(Field.Offset, SourceInfo{})) return false; - if (!this->emitRecordDestruction(D)) + if (!this->emitDestruction(D)) + return false; + if (!this->emitPopPtr(SourceInfo{})) return false; } } @@ -3437,13 +3402,57 @@ bool ByteCodeExprGen::emitRecordDestruction(const Descriptor *Desc) { for (const Record::Base &Base : llvm::reverse(R->bases())) { if (!this->emitGetPtrBase(Base.Offset, SourceInfo{})) return false; - if (!this->emitRecordDestruction(Base.Desc)) + if (!this->emitRecordDestruction(Base.R)) + return false; + if (!this->emitPopPtr(SourceInfo{})) return false; } + // FIXME: Virtual bases. + return true; +} +/// 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). +template +bool ByteCodeExprGen::emitDestruction(const Descriptor *Desc) { + assert(Desc); + assert(!Desc->isPrimitive()); + assert(!Desc->isPrimitiveArray()); + + // Arrays. + if (Desc->isArray()) { + const Descriptor *ElemDesc = Desc->ElemDesc; + assert(ElemDesc); + + // Don't need to do anything for these. + if (ElemDesc->isPrimitiveArray()) + return true; + + // If this is an array of record types, check if we need + // to call the element destructors at all. If not, try + // to save the work. + if (const Record *ElemRecord = ElemDesc->ElemRecord) { + if (const CXXDestructorDecl *Dtor = ElemRecord->getDestructor(); + !Dtor || Dtor->isTrivial()) + return true; + } + + 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->emitDestruction(ElemDesc)) + return false; + if (!this->emitPopPtr(SourceInfo{})) + return false; + } + return true; + } - // Remove the instance pointer. - return this->emitPopPtr(SourceInfo{}); + assert(Desc->ElemRecord); + return this->emitRecordDestruction(Desc->ElemRecord); } namespace clang { diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.h b/clang/lib/AST/Interp/ByteCodeExprGen.h index eeb56dc845656..abaf28ac7d447 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.h +++ b/clang/lib/AST/Interp/ByteCodeExprGen.h @@ -289,7 +289,8 @@ class ByteCodeExprGen : public ConstStmtVisitor, bool>, bool emitComplexReal(const Expr *SubExpr); - bool emitRecordDestruction(const Descriptor *Desc); + bool emitRecordDestruction(const Record *R); + bool emitDestruction(const Descriptor *Desc); unsigned collectBaseOffset(const RecordType *BaseType, const RecordType *DerivedType); @@ -401,7 +402,8 @@ template class LocalScope : public VariableScope { 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->emitDestruction(Local.Desc); + this->Ctx->emitPopPtr(SourceInfo{}); removeIfStoredOpaqueValue(Local); } }