diff options
Diffstat (limited to 'clang/lib/CodeGen')
-rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 15 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprAgg.cpp | 29 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGExprConstant.cpp | 26 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGOpenMPRuntime.cpp | 2 | ||||
-rw-r--r-- | clang/lib/CodeGen/CGRecordLayoutBuilder.cpp | 28 | ||||
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 9 |
6 files changed, 77 insertions, 32 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index a2a4bca2a5c..17bb9e937bb 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -3879,12 +3879,27 @@ LValue CodeGenFunction::EmitLValueForLambdaField(const FieldDecl *Field) { return EmitLValueForField(LambdaLV, Field); } +/// Get the address of a zero-sized field within a record. The resulting +/// address doesn't necessarily have the right type. +static Address emitAddrOfZeroSizeField(CodeGenFunction &CGF, Address Base, + const FieldDecl *Field) { + CharUnits Offset = CGF.getContext().toCharUnitsFromBits( + CGF.getContext().getFieldOffset(Field)); + if (Offset.isZero()) + return Base; + Base = CGF.Builder.CreateElementBitCast(Base, CGF.Int8Ty); + return CGF.Builder.CreateConstInBoundsByteGEP(Base, Offset); +} + /// Drill down to the storage of a field without walking into /// reference types. /// /// The resulting address doesn't necessarily have the right type. static Address emitAddrOfFieldStorage(CodeGenFunction &CGF, Address base, const FieldDecl *field) { + if (field->isZeroSize(CGF.getContext())) + return emitAddrOfZeroSizeField(CGF, base, field); + const RecordDecl *rec = field->getParent(); unsigned idx = diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp index 3b1c5bf876e..a41b420801f 100644 --- a/clang/lib/CodeGen/CGExprAgg.cpp +++ b/clang/lib/CodeGen/CGExprAgg.cpp @@ -1846,15 +1846,32 @@ LValue CodeGenFunction::EmitAggExprToLValue(const Expr *E) { return LV; } +AggValueSlot::Overlap_t +CodeGenFunction::overlapForFieldInit(const FieldDecl *FD) { + if (!FD->hasAttr<NoUniqueAddressAttr>() || !FD->getType()->isRecordType()) + return AggValueSlot::DoesNotOverlap; + + // If the field lies entirely within the enclosing class's nvsize, its tail + // padding cannot overlap any already-initialized object. (The only subobjects + // with greater addresses that might already be initialized are vbases.) + const RecordDecl *ClassRD = FD->getParent(); + const ASTRecordLayout &Layout = getContext().getASTRecordLayout(ClassRD); + if (Layout.getFieldOffset(FD->getFieldIndex()) + + getContext().getTypeSize(FD->getType()) <= + (uint64_t)getContext().toBits(Layout.getNonVirtualSize())) + return AggValueSlot::DoesNotOverlap; + + // The tail padding may contain values we need to preserve. + return AggValueSlot::MayOverlap; +} + AggValueSlot::Overlap_t CodeGenFunction::overlapForBaseInit( const CXXRecordDecl *RD, const CXXRecordDecl *BaseRD, bool IsVirtual) { - // Virtual bases are initialized first, in address order, so there's never - // any overlap during their initialization. - // - // FIXME: Under P0840, this is no longer true: the tail padding of a vbase - // of a field could be reused by a vbase of a containing class. + // If the most-derived object is a field declared with [[no_unique_address]], + // the tail padding of any virtual base could be reused for other subobjects + // of that field's class. if (IsVirtual) - return AggValueSlot::DoesNotOverlap; + return AggValueSlot::MayOverlap; // If the base class is laid out entirely within the nvsize of the derived // class, its tail padding cannot yet be initialized, so we can issue diff --git a/clang/lib/CodeGen/CGExprConstant.cpp b/clang/lib/CodeGen/CGExprConstant.cpp index e94fc67a4cb..16ccd052255 100644 --- a/clang/lib/CodeGen/CGExprConstant.cpp +++ b/clang/lib/CodeGen/CGExprConstant.cpp @@ -675,11 +675,12 @@ bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) { ++FieldNo; // If this is a union, skip all the fields that aren't being initialized. - if (RD->isUnion() && ILE->getInitializedFieldInUnion() != Field) + if (RD->isUnion() && + !declaresSameEntity(ILE->getInitializedFieldInUnion(), Field)) continue; - // Don't emit anonymous bitfields, they just affect layout. - if (Field->isUnnamedBitfield()) + // Don't emit anonymous bitfields or zero-sized fields. + if (Field->isUnnamedBitfield() || Field->isZeroSize(CGM.getContext())) continue; // Get the initializer. A struct can include fields without initializers, @@ -720,6 +721,10 @@ bool ConstStructBuilder::Build(InitListExpr *ILE, bool AllowOverwrite) { if (!AppendField(Field, Layout.getFieldOffset(FieldNo), EltInit, AllowOverwrite)) return false; + // After emitting a non-empty field with [[no_unique_address]], we may + // need to overwrite its tail padding. + if (Field->hasAttr<NoUniqueAddressAttr>()) + AllowOverwrite = true; } else { // Otherwise we have a bitfield. if (auto *CI = dyn_cast<llvm::ConstantInt>(EltInit)) { @@ -793,14 +798,15 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, unsigned FieldNo = 0; uint64_t OffsetBits = CGM.getContext().toBits(Offset); + bool AllowOverwrite = false; for (RecordDecl::field_iterator Field = RD->field_begin(), FieldEnd = RD->field_end(); Field != FieldEnd; ++Field, ++FieldNo) { // If this is a union, skip all the fields that aren't being initialized. if (RD->isUnion() && !declaresSameEntity(Val.getUnionField(), *Field)) continue; - // Don't emit anonymous bitfields, they just affect layout. - if (Field->isUnnamedBitfield()) + // Don't emit anonymous bitfields or zero-sized fields. + if (Field->isUnnamedBitfield() || Field->isZeroSize(CGM.getContext())) continue; // Emit the value of the initializer. @@ -814,12 +820,16 @@ bool ConstStructBuilder::Build(const APValue &Val, const RecordDecl *RD, if (!Field->isBitField()) { // Handle non-bitfield members. if (!AppendField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits, - EltInit)) + EltInit, AllowOverwrite)) return false; + // After emitting a non-empty field with [[no_unique_address]], we may + // need to overwrite its tail padding. + if (Field->hasAttr<NoUniqueAddressAttr>()) + AllowOverwrite = true; } else { // Otherwise we have a bitfield. if (!AppendBitField(*Field, Layout.getFieldOffset(FieldNo) + OffsetBits, - cast<llvm::ConstantInt>(EltInit))) + cast<llvm::ConstantInt>(EltInit), AllowOverwrite)) return false; } } @@ -2216,7 +2226,7 @@ static llvm::Constant *EmitNullConstant(CodeGenModule &CGM, for (const auto *Field : record->fields()) { // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) - if (!Field->isBitField()) { + if (!Field->isBitField() && !Field->isZeroSize(CGM.getContext())) { unsigned fieldIndex = layout.getLLVMFieldNo(Field); elements[fieldIndex] = CGM.EmitNullConstant(Field->getType()); } diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp index 602c9a238d4..ee5f3993940 100644 --- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -7811,7 +7811,7 @@ private: for (const auto *Field : RD->fields()) { // Fill in non-bitfields. (Bitfields always use a zero pattern, which we // will fill in later.) - if (!Field->isBitField()) { + if (!Field->isBitField() && !Field->isZeroSize(CGF.getContext())) { unsigned FieldIndex = RL.getLLVMFieldNo(Field); RecordLayout[FieldIndex] = Field; } diff --git a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp index b5102bb154c..4de64a32f2a 100644 --- a/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp +++ b/clang/lib/CodeGen/CGRecordLayoutBuilder.cpp @@ -347,18 +347,21 @@ void CGRecordLowering::lowerUnion() { void CGRecordLowering::accumulateFields() { for (RecordDecl::field_iterator Field = D->field_begin(), FieldEnd = D->field_end(); - Field != FieldEnd;) + Field != FieldEnd;) { if (Field->isBitField()) { RecordDecl::field_iterator Start = Field; // Iterate to gather the list of bitfields. for (++Field; Field != FieldEnd && Field->isBitField(); ++Field); accumulateBitFields(Start, Field); - } else { + } else if (!Field->isZeroSize(Context)) { Members.push_back(MemberInfo( bitsToCharUnits(getFieldBitOffset(*Field)), MemberInfo::Field, getStorageType(*Field), *Field)); ++Field; + } else { + ++Field; } + } } void @@ -590,10 +593,17 @@ void CGRecordLowering::clipTailPadding() { if (!Member->Data && Member->Kind != MemberInfo::Scissor) continue; if (Member->Offset < Tail) { - assert(Prior->Kind == MemberInfo::Field && !Prior->FD && + assert(Prior->Kind == MemberInfo::Field && "Only storage fields have tail padding!"); - Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo( - cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8))); + if (!Prior->FD || Prior->FD->isBitField()) + Prior->Data = getByteArrayType(bitsToCharUnits(llvm::alignTo( + cast<llvm::IntegerType>(Prior->Data)->getIntegerBitWidth(), 8))); + else { + assert(Prior->FD->hasAttr<NoUniqueAddressAttr>() && + "should not have reused this field's tail padding"); + Prior->Data = getByteArrayType( + Context.getTypeInfoDataSizeInChars(Prior->FD->getType()).first); + } } if (Member->Data) Prior = Member; @@ -797,6 +807,10 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, for (unsigned i = 0, e = AST_RL.getFieldCount(); i != e; ++i, ++it) { const FieldDecl *FD = *it; + // Ignore zero-sized fields. + if (FD->isZeroSize(getContext())) + continue; + // For non-bit-fields, just check that the LLVM struct offset matches the // AST offset. if (!FD->isBitField()) { @@ -810,10 +824,6 @@ CGRecordLayout *CodeGenTypes::ComputeRecordLayout(const RecordDecl *D, if (!FD->getDeclName()) continue; - // Don't inspect zero-length bitfields. - if (FD->isZeroLengthBitField(getContext())) - continue; - const CGBitFieldInfo &Info = RL->getBitFieldInfo(FD); llvm::Type *ElementTy = ST->getTypeAtIndex(RL->getLLVMFieldNo(FD)); diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index e95a07ce0e4..efb68c56041 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2322,14 +2322,7 @@ public: } /// Determine whether a field initialization may overlap some other object. - AggValueSlot::Overlap_t overlapForFieldInit(const FieldDecl *FD) { - // FIXME: These cases can result in overlap as a result of P0840R0's - // [[no_unique_address]] attribute. We can still infer NoOverlap in the - // presence of that attribute if the field is within the nvsize of its - // containing class, because non-virtual subobjects are initialized in - // address order. - return AggValueSlot::DoesNotOverlap; - } + AggValueSlot::Overlap_t overlapForFieldInit(const FieldDecl *FD); /// Determine whether a base class initialization may overlap some other /// object. |