diff --git a/clang/lib/CIR/CodeGen/CIRGenClass.cpp b/clang/lib/CIR/CodeGen/CIRGenClass.cpp index c54d06c1f9d1..7e62a9fcaf10 100644 --- a/clang/lib/CIR/CodeGen/CIRGenClass.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenClass.cpp @@ -252,7 +252,30 @@ static void emitMemberInitializer(CIRGenFunction &CGF, CGF.getContext().getAsConstantArrayType(FieldType); if (Array && Constructor->isDefaulted() && Constructor->isCopyOrMoveConstructor()) { - llvm_unreachable("NYI"); + 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()) { + 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; + } } CGF.emitInitializerForField(Field, LHS, MemberInit->getInit()); diff --git a/clang/test/CIR/CodeGen/copy-constructor.cpp b/clang/test/CIR/CodeGen/copy-constructor.cpp new file mode 100644 index 000000000000..92e0887b02ef --- /dev/null +++ b/clang/test/CIR/CodeGen/copy-constructor.cpp @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -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 -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +struct HasScalarArrayMember { + int arr[2][2]; + HasScalarArrayMember(const HasScalarArrayMember &); +}; + +// CIR-LABEL: cir.func @_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 +HasScalarArrayMember::HasScalarArrayMember(const HasScalarArrayMember &) = default;