diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -4623,6 +4623,10 @@ /// is declared const, return true. Otherwise, return false. bool hasConstFields() const; + /// Recursively check all fields in the record for sizeless. If any field + /// is a sizeless type, return true. Otherwise, return false. + bool hasSizelessFields() const; + bool isSugared() const { return false; } QualType desugar() const { return QualType(this, 0); } diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -3510,6 +3510,28 @@ return false; } +bool RecordType::hasSizelessFields() const { + std::vector RecordTypeList; + RecordTypeList.push_back(this); + unsigned NextToCheckIndex = 0; + + while (RecordTypeList.size() > NextToCheckIndex) { + for (FieldDecl *FD : + RecordTypeList[NextToCheckIndex]->getDecl()->fields()) { + QualType FieldTy = FD->getType(); + if (FieldTy.getTypePtr()->isSizelessType()) + return true; + FieldTy = FieldTy.getCanonicalType(); + if (const auto *FieldRecTy = FieldTy->getAs()) { + if (llvm::find(RecordTypeList, FieldRecTy) == RecordTypeList.end()) + RecordTypeList.push_back(FieldRecTy); + } + } + ++NextToCheckIndex; + } + return false; +} + bool AttributedType::isQualifier() const { // FIXME: Generate this with TableGen. switch (getAttrKind()) { diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -2077,6 +2077,23 @@ } } + // Aggregate assignment turns into element-by-element copy. + if (const RecordType *RecordTy = Ty->getAs()) { + if (RecordTy->hasSizelessFields()) { + RecordDecl *Record = RecordTy->getDecl(); + llvm::Value *SrcAgg = Builder.CreateLoad(SrcPtr); + llvm::Value *DestAgg = llvm::UndefValue::get(ConvertType(Ty)); + unsigned FieldCount = + getContext().getASTRecordLayout(Record).getFieldCount(); + for (unsigned I = 0; I < FieldCount; ++I) { + llvm::Value *Vec = Builder.CreateExtractValue(SrcAgg, I); + DestAgg = Builder.CreateInsertValue(DestAgg, Vec, I); + } + Builder.CreateStore(DestAgg, DestPtr); + return; + } + } + // Aggregate assignment turns into llvm.memcpy. This is almost valid per // C99 6.5.16.1p3, which states "If the value being stored in an object is // read from another object that overlaps in anyway the storage of the first