[clang] [CIR] Add support for member initialization from constructors (PR #144583)
Bruno Cardoso Lopes via cfe-commits
cfe-commits at lists.llvm.org
Wed Jun 18 14:56:38 PDT 2025
================
@@ -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
More information about the cfe-commits
mailing list