diff options
Diffstat (limited to 'clang/lib/CIR/CodeGen')
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenClass.cpp | 103 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 14 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenFunction.h | 27 | ||||
-rw-r--r-- | clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp | 5 |
5 files changed, 166 insertions, 5 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 8f4377b..d9ebf19 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -870,6 +870,109 @@ void CIRGenFunction::destroyCXXObject(CIRGenFunction &cgf, Address addr, /*delegating=*/false, addr, type); } +namespace { +class DestroyField final : public EHScopeStack::Cleanup { + const FieldDecl *field; + CIRGenFunction::Destroyer *destroyer; + +public: + DestroyField(const FieldDecl *field, CIRGenFunction::Destroyer *destroyer) + : field(field), destroyer(destroyer) {} + + void emit(CIRGenFunction &cgf) override { + // Find the address of the field. + Address thisValue = cgf.loadCXXThisAddress(); + CanQualType recordTy = + cgf.getContext().getCanonicalTagType(field->getParent()); + LValue thisLV = cgf.makeAddrLValue(thisValue, recordTy); + LValue lv = cgf.emitLValueForField(thisLV, field); + assert(lv.isSimple()); + + assert(!cir::MissingFeatures::ehCleanupFlags()); + cgf.emitDestroy(lv.getAddress(), field->getType(), destroyer); + } + + // This is a placeholder until EHCleanupScope is implemented. + size_t getSize() const override { + assert(!cir::MissingFeatures::ehCleanupScope()); + return sizeof(DestroyField); + } +}; +} // namespace + +/// Emit all code that comes at the end of class's destructor. This is to call +/// destructors on members and base classes in reverse order of their +/// construction. +/// +/// For a deleting destructor, this also handles the case where a destroying +/// operator delete completely overrides the definition. +void CIRGenFunction::enterDtorCleanups(const CXXDestructorDecl *dd, + CXXDtorType dtorType) { + assert((!dd->isTrivial() || dd->hasAttr<DLLExportAttr>()) && + "Should not emit dtor epilogue for non-exported trivial dtor!"); + + // The deleting-destructor phase just needs to call the appropriate + // operator delete that Sema picked up. + if (dtorType == Dtor_Deleting) { + cgm.errorNYI(dd->getSourceRange(), "deleting destructor cleanups"); + return; + } + + const CXXRecordDecl *classDecl = dd->getParent(); + + // Unions have no bases and do not call field destructors. + if (classDecl->isUnion()) + return; + + // The complete-destructor phase just destructs all the virtual bases. + if (dtorType == Dtor_Complete) { + assert(!cir::MissingFeatures::sanitizers()); + + if (classDecl->getNumVBases()) + cgm.errorNYI(dd->getSourceRange(), "virtual base destructor cleanups"); + + return; + } + + assert(dtorType == Dtor_Base); + assert(!cir::MissingFeatures::sanitizers()); + + // Destroy non-virtual bases. + for (const CXXBaseSpecifier &base : classDecl->bases()) { + // Ignore virtual bases. + if (base.isVirtual()) + continue; + + CXXRecordDecl *baseClassDecl = base.getType()->getAsCXXRecordDecl(); + + if (baseClassDecl->hasTrivialDestructor()) + assert(!cir::MissingFeatures::sanitizers()); + else + cgm.errorNYI(dd->getSourceRange(), + "non-trivial base destructor cleanups"); + } + + assert(!cir::MissingFeatures::sanitizers()); + + // Destroy direct fields. + for (const FieldDecl *field : classDecl->fields()) { + QualType type = field->getType(); + QualType::DestructionKind dtorKind = type.isDestructedType(); + if (!dtorKind) + continue; + + // Anonymous union members do not have their destructors called. + const RecordType *rt = type->getAsUnionType(); + if (rt && rt->getOriginalDecl()->isAnonymousStructOrUnion()) + continue; + + CleanupKind cleanupKind = getCleanupKind(dtorKind); + assert(!cir::MissingFeatures::ehCleanupFlags()); + ehStack.pushCleanup<DestroyField>(cleanupKind, field, + getDestroyer(dtorKind)); + } +} + void CIRGenFunction::emitDelegatingCXXConstructorCall( const CXXConstructorDecl *ctor, const FunctionArgList &args) { assert(ctor->isDelegatingConstructor()); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 5d3496a..7edd83e 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -1893,6 +1893,28 @@ mlir::Value ScalarExprEmitter::VisitCastExpr(CastExpr *ce) { } return v; } + case CK_IntegralToPointer: { + mlir::Type destCIRTy = cgf.convertType(destTy); + mlir::Value src = Visit(const_cast<Expr *>(subExpr)); + + // Properly resize by casting to an int of the same size as the pointer. + // Clang's IntegralToPointer includes 'bool' as the source, but in CIR + // 'bool' is not an integral type. So check the source type to get the + // correct CIR conversion. + mlir::Type middleTy = cgf.cgm.getDataLayout().getIntPtrType(destCIRTy); + mlir::Value middleVal = builder.createCast( + subExpr->getType()->isBooleanType() ? cir::CastKind::bool_to_int + : cir::CastKind::integral, + src, middleTy); + + if (cgf.cgm.getCodeGenOpts().StrictVTablePointers) { + cgf.cgm.errorNYI(subExpr->getSourceRange(), + "IntegralToPointer: strict vtable pointers"); + return {}; + } + + return builder.createIntToPtr(middleVal, destCIRTy); + } case CK_ArrayToPointerDecay: return cgf.emitArrayToPointerDecay(subExpr).getPointer(); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 52fb0d7..7a774e0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -689,7 +689,9 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) { cgm.errorNYI(dtor->getSourceRange(), "function-try-block destructor"); assert(!cir::MissingFeatures::sanitizers()); - assert(!cir::MissingFeatures::dtorCleanups()); + + // Enter the epilogue cleanups. + RunCleanupsScope dtorEpilogue(*this); // If this is the complete variant, just invoke the base variant; // the epilogue will destruct the virtual bases. But we can't do @@ -708,7 +710,8 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) { assert((body || getTarget().getCXXABI().isMicrosoft()) && "can't emit a dtor without a body for non-Microsoft ABIs"); - assert(!cir::MissingFeatures::dtorCleanups()); + // Enter the cleanup scopes for virtual bases. + enterDtorCleanups(dtor, Dtor_Complete); if (!isTryBody) { QualType thisTy = dtor->getFunctionObjectParameterType(); @@ -723,7 +726,9 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) { case Dtor_Base: assert(body); - assert(!cir::MissingFeatures::dtorCleanups()); + // Enter the cleanup scopes for fields and non-virtual bases. + enterDtorCleanups(dtor, Dtor_Base); + assert(!cir::MissingFeatures::vtableInitialization()); if (isTryBody) { @@ -741,7 +746,8 @@ void CIRGenFunction::emitDestructorBody(FunctionArgList &args) { break; } - assert(!cir::MissingFeatures::dtorCleanups()); + // Jump out through the epilogue cleanups. + dtorEpilogue.forceCleanup(); // Exit the try if applicable. if (isTryBody) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index a60efe1..db2adc2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -556,6 +556,33 @@ public: cir::GlobalOp gv, cir::GetGlobalOp gvAddr); + /// Enter the cleanups necessary to complete the given phase of destruction + /// for a destructor. The end result should call destructors on members and + /// base classes in reverse order of their construction. + void enterDtorCleanups(const CXXDestructorDecl *dtor, CXXDtorType type); + + /// Determines whether an EH cleanup is required to destroy a type + /// with the given destruction kind. + /// TODO(cir): could be shared with Clang LLVM codegen + bool needsEHCleanup(QualType::DestructionKind kind) { + switch (kind) { + case QualType::DK_none: + return false; + case QualType::DK_cxx_destructor: + case QualType::DK_objc_weak_lifetime: + case QualType::DK_nontrivial_c_struct: + return getLangOpts().Exceptions; + case QualType::DK_objc_strong_lifetime: + return getLangOpts().Exceptions && + cgm.getCodeGenOpts().ObjCAutoRefCountExceptions; + } + llvm_unreachable("bad destruction kind"); + } + + CleanupKind getCleanupKind(QualType::DestructionKind kind) { + return needsEHCleanup(kind) ? NormalAndEHCleanup : NormalCleanup; + } + /// Set the address of a local variable. void setAddrOfLocalVar(const clang::VarDecl *vd, Address addr) { assert(!localDeclMap.count(vd) && "Decl already exists in LocalDeclMap!"); diff --git a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp index a9af753..4cf2237 100644 --- a/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenOpenACC.cpp @@ -87,7 +87,10 @@ CIRGenFunction::getOpenACCDataOperandInfo(const Expr *e) { if (const auto *section = dyn_cast<ArraySectionExpr>(curVarExpr)) { QualType baseTy = ArraySectionExpr::getBaseOriginalType( section->getBase()->IgnoreParenImpCasts()); - boundTypes.push_back(QualType(baseTy->getPointeeOrArrayElementType(), 0)); + if (auto *at = getContext().getAsArrayType(baseTy)) + boundTypes.push_back(at->getElementType()); + else + boundTypes.push_back(baseTy->getPointeeType()); } else { boundTypes.push_back(curVarExpr->getType()); } |