================ @@ -53,19 +53,135 @@ bool CIRGenFunction::isConstructorDelegationValid( return true; } +static void emitLValueForAnyFieldInitialization(CIRGenFunction &cgf, + CXXCtorInitializer *memberInit, + LValue &lhs) { + FieldDecl *field = memberInit->getAnyMember(); + if (memberInit->isIndirectMemberInitializer()) { + // If we are initializing an anonymous union field, drill down to the field. + IndirectFieldDecl *indirectField = memberInit->getIndirectMember(); + for (const auto *nd : indirectField->chain()) { + auto *fd = cast<clang::FieldDecl>(nd); + lhs = cgf.emitLValueForFieldInitialization(lhs, fd, fd->getName()); + } + } else { + lhs = cgf.emitLValueForFieldInitialization(lhs, field, field->getName()); + } +} + +static void emitMemberInitializer(CIRGenFunction &cgf, + const CXXRecordDecl *classDecl, + CXXCtorInitializer *memberInit, + const CXXConstructorDecl *constructor, + FunctionArgList &args) { + assert(memberInit->isAnyMemberInitializer() && + "Mush have member initializer!"); + assert(memberInit->getInit() && "Must have initializer!"); + + assert(!cir::MissingFeatures::generateDebugInfo()); + + // non-static data member initializers + FieldDecl *field = memberInit->getAnyMember(); + QualType fieldType = field->getType(); + + mlir::Value thisPtr = cgf.loadCXXThis(); + QualType recordTy = cgf.getContext().getTypeDeclType(classDecl); + LValue lhs; + + // If a base constructor is being emitted, create an LValue that has the + // non-virtual alignment. + if (cgf.curGD.getCtorType() == Ctor_Base) + lhs = cgf.makeNaturalAlignPointeeAddrLValue(thisPtr, recordTy); + else + lhs = cgf.makeNaturalAlignAddrLValue(thisPtr, recordTy); + + emitLValueForAnyFieldInitialization(cgf, memberInit, lhs); + + // Special case: If we are in a copy or move constructor, and we are copying + // an array off PODs or classes with tirival copy constructors, ignore the AST + // and perform the copy we know is equivalent. + // FIXME: This is hacky at best... if we had a bit more explicit information + // in the AST, we could generalize it more easily. + const ConstantArrayType *array = + cgf.getContext().getAsConstantArrayType(fieldType); + if (array && constructor->isDefaulted() && + constructor->isCopyOrMoveConstructor()) { + QualType baseElementTy = cgf.getContext().getBaseElementType(array); + // NOTE(cir): CodeGen allows record types to be memcpy'd if applicable, + // whereas ClangIR wants to represent all object construction explicitly. + if (!baseElementTy->isRecordType()) { + cgf.cgm.errorNYI(memberInit->getSourceRange(), + "emitMemberInitializer: array of non-record type"); + return; + } + } + + cgf.emitInitializerForField(field, lhs, memberInit->getInit()); +} + /// This routine generates necessary code to initialize base classes and /// non-static data members belonging to this constructor. void CIRGenFunction::emitCtorPrologue(const CXXConstructorDecl *cd, CXXCtorType ctorType, FunctionArgList &args) { - if (cd->isDelegatingConstructor()) - return emitDelegatingCXXConstructorCall(cd, args); + if (cd->isDelegatingConstructor()) { + emitDelegatingCXXConstructorCall(cd, args); + return; + } + + // If there are no member initializers, we can just return. + if (cd->getNumCtorInitializers() == 0) + return; - if (cd->getNumCtorInitializers() != 0) { - // There's much more to do here. - cgm.errorNYI(cd->getSourceRange(), "emitCtorPrologue: any initializer"); + const CXXRecordDecl *classDecl = cd->getParent(); + + // This code doesn't use range-based iteration because we may need to emit + // code between the virtual base initializers and the non-virtual base or + // between the non-virtual base initializers and the member initializers. + CXXConstructorDecl::init_const_iterator b = cd->init_begin(), + e = cd->init_end(); + + // Virtual base initializers first, if any. They aren't needed if: + // - This is a base ctor variant + // - There are no vbases + // - The class is abstract, so a complete object of it cannot be constructed + // + // The check for an abstract class is necessary because sema may not have + // marked virtual base destructors referenced. + bool constructVBases = ctorType != Ctor_Base && + classDecl->getNumVBases() != 0 && + !classDecl->isAbstract(); + if (constructVBases) { + cgm.errorNYI(cd->getSourceRange(), "emitCtorPrologue: virtual base"); return; } + + if ((*b)->isBaseInitializer()) { + cgm.errorNYI(cd->getSourceRange(), + "emitCtorPrologue: non-virtual base initializer"); + return; + } + + if (classDecl->isDynamicClass()) { + cgm.errorNYI(cd->getSourceRange(), + "emitCtorPrologue: initialize vtable pointers"); + return; + } + + // Finally, initialize class members. + FieldConstructionScope fcs(*this, loadCXXThisAddress()); + // Classic codegen uses a special class to attempt to replace member + // initializers with memcpy. We could possibly defer that to the + // lowering or optimization phases to keep the memory accesses more + // explicit. For now, we don't insert memcpy at all. + assert(!cir::MissingFeatures::ctorMemcpyizer()); ---------------- bcardosolopes wrote:
nice! https://github.com/llvm/llvm-project/pull/144583 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits