diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index 13dc9f305945a..57b1a1f20aa17 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -192,6 +192,9 @@ class CIRGenCXXABI { QualType elementType, const CXXDestructorDecl *dtor) = 0; + virtual size_t getSrcArgforCopyCtor(const CXXConstructorDecl *, + FunctionArgList &args) const = 0; + /// Checks if ABI requires extra virtual offset for vtable field. virtual bool isVirtualOffsetNeededForVTableField(CIRGenFunction &cgf, diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index 0f10347944fae..c98d9bb0724f6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -111,8 +111,24 @@ static void emitMemberInitializer(CIRGenFunction &cgf, // 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"); + unsigned srcArgIndex = + cgf.cgm.getCXXABI().getSrcArgforCopyCtor(constructor, args); + cir::LoadOp srcPtr = cgf.getBuilder().createLoad( + cgf.getLoc(memberInit->getSourceLocation()), + cgf.getAddrOfLocalVar(args[srcArgIndex])); + LValue thisRhslv = cgf.makeNaturalAlignAddrLValue(srcPtr, recordTy); + LValue src = cgf.emitLValueForFieldInitialization(thisRhslv, field, + field->getName()); + + // Copy the aggregate. + cgf.emitAggregateCopy(lhs, src, fieldType, + cgf.getOverlapForFieldInit(field), + lhs.isVolatileQualified()); + // Ensure that we destroy the objects if an exception is thrown later in + // the constructor. + QualType::DestructionKind dtorKind = fieldType.isDestructedType(); + assert(!cgf.needsEHCleanup(dtorKind) && + "Arrays of non-record types shouldn't need EH cleanup"); return; } } diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index c98edad1303ed..7e145f2c57ce6 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -123,6 +123,12 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { return true; } + size_t getSrcArgforCopyCtor(const CXXConstructorDecl *, + FunctionArgList &args) const override { + assert(!args.empty() && "expected the arglist to not be empty!"); + return args.size() - 1; + } + void emitBadCastCall(CIRGenFunction &cgf, mlir::Location loc) override; mlir::Value diff --git a/clang/test/CIR/CodeGen/copy-constructor.cpp b/clang/test/CIR/CodeGen/copy-constructor.cpp new file mode 100644 index 0000000000000..be05bd582d6f0 --- /dev/null +++ b/clang/test/CIR/CodeGen/copy-constructor.cpp @@ -0,0 +1,52 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -mconstructor-aliases -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +struct HasScalarArrayMember { + int arr[2][2]; + HasScalarArrayMember(const HasScalarArrayMember &); +}; + +HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = default; + +// CIR-LABEL: cir.func dso_local @_ZN20HasScalarArrayMemberC2ERKS_( +// CIR-NEXT: %[[THIS:.*]] = cir.alloca !cir.ptr +// CIR-NEXT: %[[OTHER:.*]] = cir.alloca !cir.ptr +// CIR-NEXT: cir.store %arg0, %[[THIS]] +// CIR-NEXT: cir.store %arg1, %[[OTHER]] +// CIR-NEXT: %[[THIS_LOAD:.*]] = cir.load{{.*}} %[[THIS]] +// CIR-NEXT: %[[THIS_ARR:.*]] = cir.get_member %[[THIS_LOAD]][0] {name = "arr"} +// CIR-NEXT: %[[OTHER_LOAD:.*]] = cir.load{{.*}} %[[OTHER]] +// CIR-NEXT: %[[OTHER_ARR:.*]] = cir.get_member %[[OTHER_LOAD]][0] {name = "arr"} +// CIR-NEXT: cir.copy %[[OTHER_ARR]] to %[[THIS_ARR]] : !cir.ptr x 2>> +// CIR-NEXT: cir.return + +// LLVM-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_( +// LLVM-SAME: ptr %[[ARG0:.*]], ptr %[[ARG1:.*]]) +// LLVM-NEXT: %[[THIS:.*]] = alloca ptr +// LLVM-NEXT: %[[OTHER:.*]] = alloca ptr +// LLVM-NEXT: store ptr %[[ARG0]], ptr %[[THIS]] +// LLVM-NEXT: store ptr %[[ARG1]], ptr %[[OTHER]] +// LLVM-NEXT: %[[THIS_LOAD:.*]] = load ptr, ptr %[[THIS]] +// LLVM-NEXT: %[[THIS_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[THIS_LOAD]], i32 0, i32 0 +// LLVM-NEXT: %[[OTHER_LOAD:.*]] = load ptr, ptr %[[OTHER]] +// LLVM-NEXT: %[[OTHER_ARR:.*]] = getelementptr %struct.HasScalarArrayMember, ptr %[[OTHER_LOAD]], i32 0, i32 0 +// LLVM-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr %[[THIS_ARR]], ptr %[[OTHER_ARR]], i32 16, i1 false) +// LLVM-NEXT: ret void + +// OGCG-LABEL: define {{.*}} @_ZN20HasScalarArrayMemberC2ERKS_( +// OGCG-SAME: ptr {{.*}} %[[ARG0:.*]], ptr {{.*}} %[[ARG1:.*]]) +// OGCG-NEXT: entry: +// OGCG-NEXT: %[[THIS:.*]] = alloca ptr +// OGCG-NEXT: %[[OTHER:.*]] = alloca ptr +// OGCG-NEXT: store ptr %[[ARG0]], ptr %[[THIS]] +// OGCG-NEXT: store ptr %[[ARG1]], ptr %[[OTHER]] +// OGCG-NEXT: %[[THIS_LOAD:.*]] = load ptr, ptr %[[THIS]] +// OGCG-NEXT: %[[THIS_ARR:.*]] = getelementptr inbounds nuw %struct.HasScalarArrayMember, ptr %[[THIS_LOAD]], i32 0, i32 0 +// OGCG-NEXT: %[[OTHER_LOAD:.*]] = load ptr, ptr %[[OTHER]] +// OGCG-NEXT: %[[OTHER_ARR:.*]] = getelementptr inbounds nuw %struct.HasScalarArrayMember, ptr %[[OTHER_LOAD]], i32 0, i32 0 +// OGCG-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr {{.*}} %[[THIS_ARR]], ptr {{.*}} %[[OTHER_ARR]], i64 16, i1 false) +// OGCG-NEXT: ret void