=?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr>, =?utf-8?q?Théo?= De Magalhaes <theo.de-magalh...@epita.fr> Message-ID: In-Reply-To: <llvm.org/llvm/llvm-project/pull/130...@github.com>
https://github.com/therealcoochieman updated https://github.com/llvm/llvm-project/pull/130182 >From 09572af03c07966925a3456a7d51ad9b3abb750b Mon Sep 17 00:00:00 2001 From: Theo de Magalhaes <theodemagalh...@icloud.com> Date: Thu, 6 Mar 2025 22:26:37 +0100 Subject: [PATCH 01/11] chore(clang-format): formatted clang/lib/AST/RecordLayoutBuilder.cpp --- clang/lib/AST/RecordLayoutBuilder.cpp | 199 ++++++++++++-------------- 1 file changed, 94 insertions(+), 105 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 3e756ab9b9bfe..9740c8e4cdd65 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -43,7 +43,7 @@ struct BaseSubobjectInfo { bool IsVirtual; /// Bases - Information about the base subobjects. - SmallVector<BaseSubobjectInfo*, 4> Bases; + SmallVector<BaseSubobjectInfo *, 4> Bases; /// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base /// of this base info (if one exists). @@ -77,8 +77,7 @@ struct ExternalLayout { /// Get the offset of the given field. The external source must provide /// entries for all fields in the record. uint64_t getExternalFieldOffset(const FieldDecl *FD) { - assert(FieldOffsets.count(FD) && - "Field does not have an external offset"); + assert(FieldOffsets.count(FD) && "Field does not have an external offset"); return FieldOffsets[FD]; } @@ -167,16 +166,15 @@ class EmptySubobjectMap { CharUnits SizeOfLargestEmptySubobject; EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class) - : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { - ComputeEmptySubobjectSizes(); + : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { + ComputeEmptySubobjectSizes(); } /// CanPlaceBaseAtOffset - Return whether the given base class can be placed /// at the given offset. /// Returns false if placing the record will result in two components /// (direct or indirect) of the same type having the same offset. - bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, - CharUnits Offset); + bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, CharUnits Offset); /// CanPlaceFieldAtOffset - Return whether a field can be placed at the given /// offset. @@ -227,9 +225,8 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { } } -bool -EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - CharUnits Offset) const { +bool EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) const { // We only need to check empty bases. if (!RD->isEmpty()) return true; @@ -265,9 +262,8 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, MaxEmptyClassOffset = Offset; } -bool -EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, - CharUnits Offset) { +bool EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset( + const BaseSubobjectInfo *Info, CharUnits Offset) { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -368,10 +364,9 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, return true; } -bool -EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, - const CXXRecordDecl *Class, - CharUnits Offset) const { +bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset( + const CXXRecordDecl *RD, const CXXRecordDecl *Class, + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -418,9 +413,8 @@ EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, return true; } -bool -EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - CharUnits Offset) const { +bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -560,7 +554,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( } } -typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> ClassSetTy; +typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> ClassSetTy; class ItaniumRecordLayoutBuilder { protected: @@ -712,15 +706,13 @@ class ItaniumRecordLayoutBuilder { bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); - TargetCXXABI getCXXABI() const { - return Context.getTargetInfo().getCXXABI(); - } + TargetCXXABI getCXXABI() const { return Context.getTargetInfo().getCXXABI(); } /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; typedef llvm::DenseMap<const CXXRecordDecl *, BaseSubobjectInfo *> - BaseSubobjectInfoMapTy; + BaseSubobjectInfoMapTy; /// VirtualBaseInfo - Map from all the (direct or indirect) virtual bases /// of the class we're laying out to their base subobject info. @@ -793,8 +785,8 @@ class ItaniumRecordLayoutBuilder { uint64_t ComputedOffset); void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, - uint64_t UnpackedOffset, unsigned UnpackedAlign, - bool isPacked, const FieldDecl *D); + uint64_t UnpackedOffset, unsigned UnpackedAlign, + bool isPacked, const FieldDecl *D); DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); @@ -965,8 +957,7 @@ BaseSubobjectInfo *ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( // Traversing the bases must have created the base info for our primary // virtual base. PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase); - assert(PrimaryVirtualBaseInfo && - "Did not create a primary virtual base!"); + assert(PrimaryVirtualBaseInfo && "Did not create a primary virtual base!"); // Claim the primary virtual base as our primary virtual base. Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo; @@ -984,13 +975,12 @@ void ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl(); // Compute the base subobject info for this base. - BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, - nullptr); + BaseSubobjectInfo *Info = + ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, nullptr); if (IsVirtual) { // ComputeBaseInfo has already added this base for us. - assert(VirtualBaseInfo.count(BaseDecl) && - "Did not add virtual base!"); + assert(VirtualBaseInfo.count(BaseDecl) && "Did not add virtual base!"); } else { // Add the base info to the map of non-virtual bases. assert(!NonVirtualBaseInfo.count(BaseDecl) && @@ -1043,15 +1033,15 @@ void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases( LayoutVirtualBase(PrimaryBaseInfo); } else { BaseSubobjectInfo *PrimaryBaseInfo = - NonVirtualBaseInfo.lookup(PrimaryBase); + NonVirtualBaseInfo.lookup(PrimaryBase); assert(PrimaryBaseInfo && "Did not find base info for non-virtual primary base!"); LayoutNonVirtualBase(PrimaryBaseInfo); } - // If this class needs a vtable/vf-table and didn't get one from a - // primary base, add it in now. + // If this class needs a vtable/vf-table and didn't get one from a + // primary base, add it in now. } else if (RD->isDynamicClass()) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); CharUnits PtrWidth = Context.toCharUnitsFromBits( @@ -1191,8 +1181,8 @@ void ItaniumRecordLayoutBuilder::LayoutVirtualBase( // Add its base class offset. assert(!VBases.count(Base->Class) && "vbase offset already exists!"); - VBases.insert(std::make_pair(Base->Class, - ASTRecordLayout::VBaseInfo(Offset, false))); + VBases.insert( + std::make_pair(Base->Class, ASTRecordLayout::VBaseInfo(Offset, false))); AddPrimaryVirtualBaseOffsets(Base, Offset); } @@ -1450,9 +1440,8 @@ void ItaniumRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } // Rounds the specified size to have it a multiple of the char size. -static uint64_t -roundUpSizeToCharAlignment(uint64_t Size, - const ASTContext &Context) { +static uint64_t roundUpSizeToCharAlignment(uint64_t Size, + const ASTContext &Context) { uint64_t CharAlignment = Context.getTargetInfo().getCharAlign(); return llvm::alignTo(Size, CharAlignment); } @@ -1497,8 +1486,7 @@ void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; if (IsUnion) { - uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, - Context); + uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, Context); setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); FieldOffset = 0; } else { @@ -1648,7 +1636,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // Compute the next available bit offset. uint64_t FieldOffset = - IsUnion ? 0 : (getDataSizeInBits() - UnfilledBitsInLastUnit); + IsUnion ? 0 : (getDataSizeInBits() - UnfilledBitsInLastUnit); // Handle targets that don't honor bitfield type alignment. if (!IsMsStruct && !Context.getTargetInfo().useBitFieldTypeAlignment()) { @@ -1666,7 +1654,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { Context.getTargetInfo().getZeroLengthBitfieldBoundary(); FieldAlign = std::max(FieldAlign, ZeroLengthBitfieldBoundary); } - // If that doesn't apply, just ignore the field alignment. + // If that doesn't apply, just ignore the field alignment. } else { FieldAlign = 1; } @@ -1810,8 +1798,8 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { } setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); - // For non-zero-width bitfields in ms_struct structs, allocate a new - // storage unit if necessary. + // For non-zero-width bitfields in ms_struct structs, allocate a new + // storage unit if necessary. } else if (IsMsStruct && FieldSize) { // We should have cleared UnfilledBitsInLastUnit in every case // where we changed storage units. @@ -1960,13 +1948,13 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } } - bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() || - FieldClass->hasAttr<PackedAttr>() || - Context.getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver15 || - Target.isPS() || Target.isOSDarwin() || - Target.isOSAIX())) || - D->hasAttr<PackedAttr>(); + bool FieldPacked = + (Packed && (!FieldClass || FieldClass->isPOD() || + FieldClass->hasAttr<PackedAttr>() || + Context.getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver15 || + Target.isPS() || Target.isOSDarwin() || Target.isOSAIX())) || + D->hasAttr<PackedAttr>(); // When used as part of a typedef, or together with a 'packed' attribute, the // 'aligned' attribute can be used to decrease alignment. In that case, it @@ -2036,7 +2024,6 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); } - if (!FieldPacked) FieldAlign = UnpackedFieldAlign; if (DefaultsToAIXPowerAlignment) @@ -2142,8 +2129,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // array of zero-length, remains of Size 0 if (RD->isEmpty()) setSize(CharUnits::One()); - } - else + } else setSize(CharUnits::One()); } @@ -2190,8 +2176,7 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { InBits = false; } Diag(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) - << PadSize + << Context.getTypeDeclType(RD) << PadSize << (InBits ? 1 : 0); // (byte|bit) } @@ -2270,7 +2255,8 @@ static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { return 1; case TagTypeKind::Class: return 2; - default: llvm_unreachable("Invalid tag kind for field padding diagnostic!"); + default: + llvm_unreachable("Invalid tag kind for field padding diagnostic!"); } } @@ -2313,10 +2299,10 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding( << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) } - } - if (isPacked && Offset != UnpackedOffset) { - HasPackedField = true; - } + } + if (isPacked && Offset != UnpackedOffset) { + HasPackedField = true; + } } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, @@ -2340,7 +2326,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, return nullptr; bool allowInlineFunctions = - Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline(); + Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline(); for (const CXXMethodDecl *MD : RD->methods()) { if (!MD->isVirtual()) @@ -2560,6 +2546,7 @@ struct MicrosoftRecordLayoutBuilder { private: MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) = delete; void operator=(const MicrosoftRecordLayoutBuilder &) = delete; + public: void layout(const RecordDecl *RD); void cxxLayout(const CXXRecordDecl *RD); @@ -2684,15 +2671,15 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // the alignment in the case of pragma pack. Note that the required alignment // doesn't actually apply to the struct alignment at this point. Alignment = std::max(Alignment, Info.Alignment); - RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment()); + RequiredAlignment = + std::max(RequiredAlignment, Layout.getRequiredAlignment()); Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment()); Info.Size = Layout.getNonVirtualSize(); return Info; } MicrosoftRecordLayoutBuilder::ElementInfo -MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( - const FieldDecl *FD) { +MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(const FieldDecl *FD) { // Get the alignment of the field type's natural alignment, ignore any // alignment attributes. auto TInfo = @@ -2715,8 +2702,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { auto const &Layout = Context.getASTRecordLayout(RT->getDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); - FieldRequiredAlignment = std::max(FieldRequiredAlignment, - Layout.getRequiredAlignment()); + FieldRequiredAlignment = + std::max(FieldRequiredAlignment, Layout.getRequiredAlignment()); } // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); @@ -2778,10 +2765,11 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { MaxFieldAlignment = CharUnits::Zero(); // Honor the default struct packing maximum alignment flag. if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) - MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); // Honor the packing attribute. The MS-ABI ignores pragma pack if its larger // than the pointer size. - if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){ + if (const MaxFieldAlignmentAttr *MFAA = + RD->getAttr<MaxFieldAlignmentAttr>()) { unsigned PackedAlignment = MFAA->getAlignment(); if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(LangAS::Default)) @@ -2799,8 +2787,8 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { External.BaseOffsets, External.VirtualBaseOffsets); } -void -MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { +void MicrosoftRecordLayoutBuilder::initializeCXXLayout( + const CXXRecordDecl *RD) { EndsWithZeroSizedObject = false; LeadsWithZeroSizedBase = false; HasOwnVFPtr = false; @@ -2818,8 +2806,8 @@ MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment); } -void -MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { +void MicrosoftRecordLayoutBuilder::layoutNonVirtualBases( + const CXXRecordDecl *RD) { // The MS-ABI lays out all bases that contain leading vfptrs before it lays // out any bases that do not contain vfptrs. We implement this as two passes // over the bases. This approach guarantees that the primary base is laid out @@ -3057,8 +3045,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { DataSize = Size; } -void -MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { +void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField( + const FieldDecl *FD) { // Zero-width bitfields are ignored unless they follow a non-zero-width // bitfield. if (!LastFieldIsNonZeroWidthBitfield) { @@ -3195,8 +3183,8 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { assert(BaseOffset >= Size && "base offset already allocated"); - VBases.insert(std::make_pair(BaseDecl, - ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); + VBases.insert(std::make_pair( + BaseDecl, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); Size = BaseOffset + BaseLayout.getNonVirtualSize(); PreviousBaseLayout = &BaseLayout; } @@ -3236,10 +3224,9 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { // Recursively walks the non-virtual bases of a class and determines if any of // them are in the bases with overridden methods set. -static bool -RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> & - BasesWithOverriddenMethods, - const CXXRecordDecl *RD) { +static bool RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> + &BasesWithOverriddenMethods, + const CXXRecordDecl *RD) { if (BasesWithOverriddenMethods.count(RD)) return true; // If any of a virtual bases non-virtual bases (recursively) requires a @@ -3329,7 +3316,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { // until we *finish* parsing the definition. if (D->hasExternalLexicalStorage() && !D->getDefinition()) - getExternalSource()->CompleteType(const_cast<RecordDecl*>(D)); + getExternalSource()->CompleteType(const_cast<RecordDecl *>(D)); // Complete the redecl chain (if necessary). (void)D->getMostRecentDecl(); @@ -3342,7 +3329,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { // Note that we can't save a reference to the entry because this function // is recursive. const ASTRecordLayout *Entry = ASTRecordLayouts[D]; - if (Entry) return *Entry; + if (Entry) + return *Entry; const ASTRecordLayout *NewEntry = nullptr; @@ -3418,7 +3406,8 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { return *NewEntry; } -const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { +const CXXMethodDecl * +ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { if (!getTargetInfo().getCXXABI().hasKeyFunctions()) return nullptr; @@ -3436,7 +3425,7 @@ const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) // Store it back if it changed. if (Entry.isOffset() || Entry.isValid() != bool(Result)) - KeyFunctions[RD] = const_cast<Decl*>(Result); + KeyFunctions[RD] = const_cast<Decl *>(Result); return cast_or_null<CXXMethodDecl>(Result); } @@ -3452,7 +3441,8 @@ void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { auto I = Map.find(Method->getParent()); // If it's not cached, there's nothing to do. - if (I == Map.end()) return; + if (I == Map.end()) + return; // If it is cached, check whether it's the target method, and if so, // remove it from the cache. Note, the call to 'get' might invalidate @@ -3497,8 +3487,8 @@ uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID, // directly. unsigned Index = 0; - for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); - IVD; IVD = IVD->getNextIvar()) { + for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); IVD; + IVD = IVD->getNextIvar()) { if (Ivar == IVD) break; ++Index; @@ -3517,7 +3507,7 @@ const ASTRecordLayout & ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const { // Retrieve the definition if (D->hasExternalLexicalStorage() && !D->getDefinition()) - getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl*>(D)); + getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl *>(D)); D = D->getDefinition(); assert(D && !D->isInvalidDecl() && D->isThisDeclarationADefinition() && "Invalid interface decl!"); @@ -3540,8 +3530,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const { return *NewEntry; } -static void PrintOffset(raw_ostream &OS, - CharUnits Offset, unsigned IndentLevel) { +static void PrintOffset(raw_ostream &OS, CharUnits Offset, + unsigned IndentLevel) { OS << llvm::format("%10" PRId64 " | ", (int64_t)Offset.getQuantity()); OS.indent(IndentLevel * 2); } @@ -3570,12 +3560,9 @@ static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) { } static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, - const ASTContext &C, - CharUnits Offset, - unsigned IndentLevel, - const char* Description, - bool PrintSizeInfo, - bool IncludeVirtualBases) { + const ASTContext &C, CharUnits Offset, + unsigned IndentLevel, const char *Description, + bool PrintSizeInfo, bool IncludeVirtualBases) { const ASTRecordLayout &Layout = C.getASTRecordLayout(RD); auto CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -3641,7 +3628,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, uint64_t LocalFieldOffsetInBits = Layout.getFieldOffset(Field->getFieldIndex()); CharUnits FieldOffset = - Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); + Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); // Recursively dump fields of record type. if (auto RT = Field->getType()->getAs<RecordType>()) { @@ -3669,7 +3656,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, // Dump virtual bases. if (CXXRD && IncludeVirtualBases) { const ASTRecordLayout::VBaseOffsetsMapTy &VtorDisps = - Layout.getVBaseOffsetsMap(); + Layout.getVBaseOffsetsMap(); for (const CXXBaseSpecifier &Base : CXXRD->vbases()) { assert(Base.isVirtual() && "Found non-virtual class!"); @@ -3683,14 +3670,16 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, } DumpRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, - VBase == Layout.getPrimaryBase() ? - "(primary virtual base)" : "(virtual base)", + VBase == Layout.getPrimaryBase() + ? "(primary virtual base)" + : "(virtual base)", /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/false); } } - if (!PrintSizeInfo) return; + if (!PrintSizeInfo) + return; PrintIndentNoOffset(OS, IndentLevel - 1); OS << "[sizeof=" << Layout.getSize().getQuantity(); >From 60ddbafd6c55c35fee92a0681f60305d3efa8cde Mon Sep 17 00:00:00 2001 From: Theo de Magalhaes <theodemagalh...@icloud.com> Date: Thu, 6 Mar 2025 22:48:49 +0100 Subject: [PATCH 02/11] fix(clang-cl): added -Wpadded and -Wpadded-bitfield warning --- clang/lib/AST/RecordLayoutBuilder.cpp | 86 ++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 9740c8e4cdd65..d4164179c67af 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2592,6 +2592,8 @@ struct MicrosoftRecordLayoutBuilder { void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; + void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, + const FieldDecl *D); const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -2629,8 +2631,6 @@ struct MicrosoftRecordLayoutBuilder { /// virtual base classes and their offsets in the record. ASTRecordLayout::VBaseOffsetsMapTy VBases; /// The number of remaining bits in our last bitfield allocation. - /// This value isn't meaningful unless LastFieldIsNonZeroWidthBitfield is - /// true. unsigned RemainingBitsInField; bool IsUnion : 1; /// True if the last field laid out was a bitfield and was not 0 @@ -2992,6 +2992,15 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { } else { FieldOffset = Size.alignTo(Info.Alignment); } + + uint64_t UnpaddedFielddOffsetInBits = + Context.toBits(DataSize) - RemainingBitsInField; + + CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFielddOffsetInBits, + FD); + + RemainingBitsInField = 0; + placeFieldAtOffset(FieldOffset); if (!IsOverlappingEmptyField) @@ -3037,10 +3046,14 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { } else { // Allocate a new block of memory and place the bitfield in it. CharUnits FieldOffset = Size.alignTo(Info.Alignment); + uint64_t UnpaddedFieldOffsetInBits = + Context.toBits(DataSize) - RemainingBitsInField; placeFieldAtOffset(FieldOffset); Size = FieldOffset + Info.Size; Alignment = std::max(Alignment, Info.Alignment); RemainingBitsInField = Context.toBits(Info.Size) - Width; + CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffsetInBits, + FD); } DataSize = Size; } @@ -3064,9 +3077,14 @@ void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField( } else { // Round up the current record size to the field's alignment boundary. CharUnits FieldOffset = Size.alignTo(Info.Alignment); + uint64_t UnpaddedFieldOffsetInBits = + Context.toBits(DataSize) - RemainingBitsInField; placeFieldAtOffset(FieldOffset); + RemainingBitsInField = 0; Size = FieldOffset; Alignment = std::max(Alignment, Info.Alignment); + CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffsetInBits, + FD); } DataSize = Size; } @@ -3189,8 +3207,56 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { PreviousBaseLayout = &BaseLayout; } } +// Function based on ItaniumRecordLayoutBuilder::CheckFieldPadding. +void MicrosoftRecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, + uint64_t UnpaddedOffset, + const FieldDecl *D) { + + // We let objc ivars without warning, objc interfaces generally are not used + // for padding tricks. + if (isa<ObjCIvarDecl>(D)) + return; + + // Don't warn about structs created without a SourceLocation. This can + // be done by clients of the AST, such as codegen. + if (D->getLocation().isInvalid()) + return; + + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); + + // Warn if padding was introduced to the struct/class. + if (!IsUnion && Offset > UnpaddedOffset) { + unsigned PadSize = Offset - UnpaddedOffset; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + if (D->getIdentifier()) { + auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_bitfield + : diag::warn_padded_struct_field; + Context.getDiagnostics().Report(D->getLocation(), + Diagnostic) + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) + << Context.getTypeDeclType(D->getParent()) << PadSize + << (InBits ? 1 : 0) // (byte|bit) + << D->getIdentifier(); + } else { + auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_anon_bitfield + : diag::warn_padded_struct_anon_field; + Context.getDiagnostics().Report(D->getLocation(), + Diagnostic) + << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) + << Context.getTypeDeclType(D->getParent()) << PadSize + << (InBits ? 1 : 0); // (byte|bit) + } + } +} void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { + uint64_t UnpaddedSizeInBits = Context.toBits(DataSize); + UnpaddedSizeInBits -= RemainingBitsInField; + // Respect required alignment. Note that in 32-bit mode Required alignment // may be 0 and cause size not to be updated. DataSize = Size; @@ -3219,6 +3285,22 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { Size = Context.toCharUnitsFromBits(External.Size); if (External.Align) Alignment = Context.toCharUnitsFromBits(External.Align); + return; + } + unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); + uint64_t SizeInBits = Context.toBits(Size); + if (SizeInBits > UnpaddedSizeInBits) { + unsigned int PadSize = SizeInBits - UnpaddedSizeInBits; + bool InBits = true; + if (PadSize % CharBitNum == 0) { + PadSize = PadSize / CharBitNum; + InBits = false; + } + + Context.getDiagnostics().Report(RD->getLocation(), + diag::warn_padded_struct_size) + << Context.getTypeDeclType(RD) << PadSize + << (InBits ? 1 : 0); // (byte|bit) } } >From 05048948ef58aaca06f72359899984a313bca5bc Mon Sep 17 00:00:00 2001 From: Theo de Magalhaes <theodemagalh...@icloud.com> Date: Fri, 7 Mar 2025 10:17:48 +0100 Subject: [PATCH 03/11] Revert "chore(clang-format): formatted clang/lib/AST/RecordLayoutBuilder.cpp" This reverts commit 3a9bc908a791669c82f288ff745664411bf285ac. --- clang/lib/AST/RecordLayoutBuilder.cpp | 199 ++++++++++++++------------ 1 file changed, 105 insertions(+), 94 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index d4164179c67af..68d70ebadddcb 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -43,7 +43,7 @@ struct BaseSubobjectInfo { bool IsVirtual; /// Bases - Information about the base subobjects. - SmallVector<BaseSubobjectInfo *, 4> Bases; + SmallVector<BaseSubobjectInfo*, 4> Bases; /// PrimaryVirtualBaseInfo - Holds the base info for the primary virtual base /// of this base info (if one exists). @@ -77,7 +77,8 @@ struct ExternalLayout { /// Get the offset of the given field. The external source must provide /// entries for all fields in the record. uint64_t getExternalFieldOffset(const FieldDecl *FD) { - assert(FieldOffsets.count(FD) && "Field does not have an external offset"); + assert(FieldOffsets.count(FD) && + "Field does not have an external offset"); return FieldOffsets[FD]; } @@ -166,15 +167,16 @@ class EmptySubobjectMap { CharUnits SizeOfLargestEmptySubobject; EmptySubobjectMap(const ASTContext &Context, const CXXRecordDecl *Class) - : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { - ComputeEmptySubobjectSizes(); + : Context(Context), CharWidth(Context.getCharWidth()), Class(Class) { + ComputeEmptySubobjectSizes(); } /// CanPlaceBaseAtOffset - Return whether the given base class can be placed /// at the given offset. /// Returns false if placing the record will result in two components /// (direct or indirect) of the same type having the same offset. - bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, CharUnits Offset); + bool CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset); /// CanPlaceFieldAtOffset - Return whether a field can be placed at the given /// offset. @@ -225,8 +227,9 @@ void EmptySubobjectMap::ComputeEmptySubobjectSizes() { } } -bool EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, - CharUnits Offset) const { +bool +EmptySubobjectMap::CanPlaceSubobjectAtOffset(const CXXRecordDecl *RD, + CharUnits Offset) const { // We only need to check empty bases. if (!RD->isEmpty()) return true; @@ -262,8 +265,9 @@ void EmptySubobjectMap::AddSubobjectAtOffset(const CXXRecordDecl *RD, MaxEmptyClassOffset = Offset; } -bool EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset( - const BaseSubobjectInfo *Info, CharUnits Offset) { +bool +EmptySubobjectMap::CanPlaceBaseSubobjectAtOffset(const BaseSubobjectInfo *Info, + CharUnits Offset) { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -364,9 +368,10 @@ bool EmptySubobjectMap::CanPlaceBaseAtOffset(const BaseSubobjectInfo *Info, return true; } -bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset( - const CXXRecordDecl *RD, const CXXRecordDecl *Class, - CharUnits Offset) const { +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const CXXRecordDecl *RD, + const CXXRecordDecl *Class, + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -413,8 +418,9 @@ bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset( return true; } -bool EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, - CharUnits Offset) const { +bool +EmptySubobjectMap::CanPlaceFieldSubobjectAtOffset(const FieldDecl *FD, + CharUnits Offset) const { // We don't have to keep looking past the maximum offset that's known to // contain an empty class. if (!AnyEmptySubobjectsBeyondOffset(Offset)) @@ -554,7 +560,7 @@ void EmptySubobjectMap::UpdateEmptyFieldSubobjects( } } -typedef llvm::SmallPtrSet<const CXXRecordDecl *, 4> ClassSetTy; +typedef llvm::SmallPtrSet<const CXXRecordDecl*, 4> ClassSetTy; class ItaniumRecordLayoutBuilder { protected: @@ -706,13 +712,15 @@ class ItaniumRecordLayoutBuilder { bool FieldPacked, const FieldDecl *D); void LayoutBitField(const FieldDecl *D); - TargetCXXABI getCXXABI() const { return Context.getTargetInfo().getCXXABI(); } + TargetCXXABI getCXXABI() const { + return Context.getTargetInfo().getCXXABI(); + } /// BaseSubobjectInfoAllocator - Allocator for BaseSubobjectInfo objects. llvm::SpecificBumpPtrAllocator<BaseSubobjectInfo> BaseSubobjectInfoAllocator; typedef llvm::DenseMap<const CXXRecordDecl *, BaseSubobjectInfo *> - BaseSubobjectInfoMapTy; + BaseSubobjectInfoMapTy; /// VirtualBaseInfo - Map from all the (direct or indirect) virtual bases /// of the class we're laying out to their base subobject info. @@ -785,8 +793,8 @@ class ItaniumRecordLayoutBuilder { uint64_t ComputedOffset); void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, - uint64_t UnpackedOffset, unsigned UnpackedAlign, - bool isPacked, const FieldDecl *D); + uint64_t UnpackedOffset, unsigned UnpackedAlign, + bool isPacked, const FieldDecl *D); DiagnosticBuilder Diag(SourceLocation Loc, unsigned DiagID); @@ -957,7 +965,8 @@ BaseSubobjectInfo *ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( // Traversing the bases must have created the base info for our primary // virtual base. PrimaryVirtualBaseInfo = VirtualBaseInfo.lookup(PrimaryVirtualBase); - assert(PrimaryVirtualBaseInfo && "Did not create a primary virtual base!"); + assert(PrimaryVirtualBaseInfo && + "Did not create a primary virtual base!"); // Claim the primary virtual base as our primary virtual base. Info->PrimaryVirtualBaseInfo = PrimaryVirtualBaseInfo; @@ -975,12 +984,13 @@ void ItaniumRecordLayoutBuilder::ComputeBaseSubobjectInfo( const CXXRecordDecl *BaseDecl = I.getType()->getAsCXXRecordDecl(); // Compute the base subobject info for this base. - BaseSubobjectInfo *Info = - ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, nullptr); + BaseSubobjectInfo *Info = ComputeBaseSubobjectInfo(BaseDecl, IsVirtual, + nullptr); if (IsVirtual) { // ComputeBaseInfo has already added this base for us. - assert(VirtualBaseInfo.count(BaseDecl) && "Did not add virtual base!"); + assert(VirtualBaseInfo.count(BaseDecl) && + "Did not add virtual base!"); } else { // Add the base info to the map of non-virtual bases. assert(!NonVirtualBaseInfo.count(BaseDecl) && @@ -1033,15 +1043,15 @@ void ItaniumRecordLayoutBuilder::LayoutNonVirtualBases( LayoutVirtualBase(PrimaryBaseInfo); } else { BaseSubobjectInfo *PrimaryBaseInfo = - NonVirtualBaseInfo.lookup(PrimaryBase); + NonVirtualBaseInfo.lookup(PrimaryBase); assert(PrimaryBaseInfo && "Did not find base info for non-virtual primary base!"); LayoutNonVirtualBase(PrimaryBaseInfo); } - // If this class needs a vtable/vf-table and didn't get one from a - // primary base, add it in now. + // If this class needs a vtable/vf-table and didn't get one from a + // primary base, add it in now. } else if (RD->isDynamicClass()) { assert(DataSize == 0 && "Vtable pointer must be at offset zero!"); CharUnits PtrWidth = Context.toCharUnitsFromBits( @@ -1181,8 +1191,8 @@ void ItaniumRecordLayoutBuilder::LayoutVirtualBase( // Add its base class offset. assert(!VBases.count(Base->Class) && "vbase offset already exists!"); - VBases.insert( - std::make_pair(Base->Class, ASTRecordLayout::VBaseInfo(Offset, false))); + VBases.insert(std::make_pair(Base->Class, + ASTRecordLayout::VBaseInfo(Offset, false))); AddPrimaryVirtualBaseOffsets(Base, Offset); } @@ -1440,8 +1450,9 @@ void ItaniumRecordLayoutBuilder::LayoutFields(const RecordDecl *D) { } // Rounds the specified size to have it a multiple of the char size. -static uint64_t roundUpSizeToCharAlignment(uint64_t Size, - const ASTContext &Context) { +static uint64_t +roundUpSizeToCharAlignment(uint64_t Size, + const ASTContext &Context) { uint64_t CharAlignment = Context.getTargetInfo().getCharAlign(); return llvm::alignTo(Size, CharAlignment); } @@ -1486,7 +1497,8 @@ void ItaniumRecordLayoutBuilder::LayoutWideBitField(uint64_t FieldSize, uint64_t UnpaddedFieldOffset = getDataSizeInBits() - UnfilledBitsInLastUnit; if (IsUnion) { - uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, Context); + uint64_t RoundedFieldSize = roundUpSizeToCharAlignment(FieldSize, + Context); setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); FieldOffset = 0; } else { @@ -1636,7 +1648,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { // Compute the next available bit offset. uint64_t FieldOffset = - IsUnion ? 0 : (getDataSizeInBits() - UnfilledBitsInLastUnit); + IsUnion ? 0 : (getDataSizeInBits() - UnfilledBitsInLastUnit); // Handle targets that don't honor bitfield type alignment. if (!IsMsStruct && !Context.getTargetInfo().useBitFieldTypeAlignment()) { @@ -1654,7 +1666,7 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { Context.getTargetInfo().getZeroLengthBitfieldBoundary(); FieldAlign = std::max(FieldAlign, ZeroLengthBitfieldBoundary); } - // If that doesn't apply, just ignore the field alignment. + // If that doesn't apply, just ignore the field alignment. } else { FieldAlign = 1; } @@ -1798,8 +1810,8 @@ void ItaniumRecordLayoutBuilder::LayoutBitField(const FieldDecl *D) { } setDataSize(std::max(getDataSizeInBits(), RoundedFieldSize)); - // For non-zero-width bitfields in ms_struct structs, allocate a new - // storage unit if necessary. + // For non-zero-width bitfields in ms_struct structs, allocate a new + // storage unit if necessary. } else if (IsMsStruct && FieldSize) { // We should have cleared UnfilledBitsInLastUnit in every case // where we changed storage units. @@ -1948,13 +1960,13 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, } } - bool FieldPacked = - (Packed && (!FieldClass || FieldClass->isPOD() || - FieldClass->hasAttr<PackedAttr>() || - Context.getLangOpts().getClangABICompat() <= - LangOptions::ClangABI::Ver15 || - Target.isPS() || Target.isOSDarwin() || Target.isOSAIX())) || - D->hasAttr<PackedAttr>(); + bool FieldPacked = (Packed && (!FieldClass || FieldClass->isPOD() || + FieldClass->hasAttr<PackedAttr>() || + Context.getLangOpts().getClangABICompat() <= + LangOptions::ClangABI::Ver15 || + Target.isPS() || Target.isOSDarwin() || + Target.isOSAIX())) || + D->hasAttr<PackedAttr>(); // When used as part of a typedef, or together with a 'packed' attribute, the // 'aligned' attribute can be used to decrease alignment. In that case, it @@ -2024,6 +2036,7 @@ void ItaniumRecordLayoutBuilder::LayoutField(const FieldDecl *D, UnpackedFieldAlign = std::min(UnpackedFieldAlign, MaxFieldAlignment); } + if (!FieldPacked) FieldAlign = UnpackedFieldAlign; if (DefaultsToAIXPowerAlignment) @@ -2129,7 +2142,8 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { // array of zero-length, remains of Size 0 if (RD->isEmpty()) setSize(CharUnits::One()); - } else + } + else setSize(CharUnits::One()); } @@ -2176,7 +2190,8 @@ void ItaniumRecordLayoutBuilder::FinishLayout(const NamedDecl *D) { InBits = false; } Diag(RD->getLocation(), diag::warn_padded_struct_size) - << Context.getTypeDeclType(RD) << PadSize + << Context.getTypeDeclType(RD) + << PadSize << (InBits ? 1 : 0); // (byte|bit) } @@ -2255,8 +2270,7 @@ static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { return 1; case TagTypeKind::Class: return 2; - default: - llvm_unreachable("Invalid tag kind for field padding diagnostic!"); + default: llvm_unreachable("Invalid tag kind for field padding diagnostic!"); } } @@ -2299,10 +2313,10 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding( << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) } - } - if (isPacked && Offset != UnpackedOffset) { - HasPackedField = true; - } + } + if (isPacked && Offset != UnpackedOffset) { + HasPackedField = true; + } } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, @@ -2326,7 +2340,7 @@ static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, return nullptr; bool allowInlineFunctions = - Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline(); + Context.getTargetInfo().getCXXABI().canKeyFunctionBeInline(); for (const CXXMethodDecl *MD : RD->methods()) { if (!MD->isVirtual()) @@ -2546,7 +2560,6 @@ struct MicrosoftRecordLayoutBuilder { private: MicrosoftRecordLayoutBuilder(const MicrosoftRecordLayoutBuilder &) = delete; void operator=(const MicrosoftRecordLayoutBuilder &) = delete; - public: void layout(const RecordDecl *RD); void cxxLayout(const CXXRecordDecl *RD); @@ -2671,15 +2684,15 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( // the alignment in the case of pragma pack. Note that the required alignment // doesn't actually apply to the struct alignment at this point. Alignment = std::max(Alignment, Info.Alignment); - RequiredAlignment = - std::max(RequiredAlignment, Layout.getRequiredAlignment()); + RequiredAlignment = std::max(RequiredAlignment, Layout.getRequiredAlignment()); Info.Alignment = std::max(Info.Alignment, Layout.getRequiredAlignment()); Info.Size = Layout.getNonVirtualSize(); return Info; } MicrosoftRecordLayoutBuilder::ElementInfo -MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(const FieldDecl *FD) { +MicrosoftRecordLayoutBuilder::getAdjustedElementInfo( + const FieldDecl *FD) { // Get the alignment of the field type's natural alignment, ignore any // alignment attributes. auto TInfo = @@ -2702,8 +2715,8 @@ MicrosoftRecordLayoutBuilder::getAdjustedElementInfo(const FieldDecl *FD) { FD->getType()->getBaseElementTypeUnsafe()->getAs<RecordType>()) { auto const &Layout = Context.getASTRecordLayout(RT->getDecl()); EndsWithZeroSizedObject = Layout.endsWithZeroSizedObject(); - FieldRequiredAlignment = - std::max(FieldRequiredAlignment, Layout.getRequiredAlignment()); + FieldRequiredAlignment = std::max(FieldRequiredAlignment, + Layout.getRequiredAlignment()); } // Capture required alignment as a side-effect. RequiredAlignment = std::max(RequiredAlignment, FieldRequiredAlignment); @@ -2765,11 +2778,10 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { MaxFieldAlignment = CharUnits::Zero(); // Honor the default struct packing maximum alignment flag. if (unsigned DefaultMaxFieldAlignment = Context.getLangOpts().PackStruct) - MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); + MaxFieldAlignment = CharUnits::fromQuantity(DefaultMaxFieldAlignment); // Honor the packing attribute. The MS-ABI ignores pragma pack if its larger // than the pointer size. - if (const MaxFieldAlignmentAttr *MFAA = - RD->getAttr<MaxFieldAlignmentAttr>()) { + if (const MaxFieldAlignmentAttr *MFAA = RD->getAttr<MaxFieldAlignmentAttr>()){ unsigned PackedAlignment = MFAA->getAlignment(); if (PackedAlignment <= Context.getTargetInfo().getPointerWidth(LangAS::Default)) @@ -2787,8 +2799,8 @@ void MicrosoftRecordLayoutBuilder::initializeLayout(const RecordDecl *RD) { External.BaseOffsets, External.VirtualBaseOffsets); } -void MicrosoftRecordLayoutBuilder::initializeCXXLayout( - const CXXRecordDecl *RD) { +void +MicrosoftRecordLayoutBuilder::initializeCXXLayout(const CXXRecordDecl *RD) { EndsWithZeroSizedObject = false; LeadsWithZeroSizedBase = false; HasOwnVFPtr = false; @@ -2806,8 +2818,8 @@ void MicrosoftRecordLayoutBuilder::initializeCXXLayout( PointerInfo.Alignment = std::min(PointerInfo.Alignment, MaxFieldAlignment); } -void MicrosoftRecordLayoutBuilder::layoutNonVirtualBases( - const CXXRecordDecl *RD) { +void +MicrosoftRecordLayoutBuilder::layoutNonVirtualBases(const CXXRecordDecl *RD) { // The MS-ABI lays out all bases that contain leading vfptrs before it lays // out any bases that do not contain vfptrs. We implement this as two passes // over the bases. This approach guarantees that the primary base is laid out @@ -3058,8 +3070,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { DataSize = Size; } -void MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField( - const FieldDecl *FD) { +void +MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { // Zero-width bitfields are ignored unless they follow a non-zero-width // bitfield. if (!LastFieldIsNonZeroWidthBitfield) { @@ -3201,8 +3213,8 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { assert(BaseOffset >= Size && "base offset already allocated"); - VBases.insert(std::make_pair( - BaseDecl, ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); + VBases.insert(std::make_pair(BaseDecl, + ASTRecordLayout::VBaseInfo(BaseOffset, HasVtordisp))); Size = BaseOffset + BaseLayout.getNonVirtualSize(); PreviousBaseLayout = &BaseLayout; } @@ -3306,9 +3318,10 @@ void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { // Recursively walks the non-virtual bases of a class and determines if any of // them are in the bases with overridden methods set. -static bool RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> - &BasesWithOverriddenMethods, - const CXXRecordDecl *RD) { +static bool +RequiresVtordisp(const llvm::SmallPtrSetImpl<const CXXRecordDecl *> & + BasesWithOverriddenMethods, + const CXXRecordDecl *RD) { if (BasesWithOverriddenMethods.count(RD)) return true; // If any of a virtual bases non-virtual bases (recursively) requires a @@ -3398,7 +3411,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { // until we *finish* parsing the definition. if (D->hasExternalLexicalStorage() && !D->getDefinition()) - getExternalSource()->CompleteType(const_cast<RecordDecl *>(D)); + getExternalSource()->CompleteType(const_cast<RecordDecl*>(D)); // Complete the redecl chain (if necessary). (void)D->getMostRecentDecl(); @@ -3411,8 +3424,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { // Note that we can't save a reference to the entry because this function // is recursive. const ASTRecordLayout *Entry = ASTRecordLayouts[D]; - if (Entry) - return *Entry; + if (Entry) return *Entry; const ASTRecordLayout *NewEntry = nullptr; @@ -3488,8 +3500,7 @@ ASTContext::getASTRecordLayout(const RecordDecl *D) const { return *NewEntry; } -const CXXMethodDecl * -ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { +const CXXMethodDecl *ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { if (!getTargetInfo().getCXXABI().hasKeyFunctions()) return nullptr; @@ -3507,7 +3518,7 @@ ASTContext::getCurrentKeyFunction(const CXXRecordDecl *RD) { // Store it back if it changed. if (Entry.isOffset() || Entry.isValid() != bool(Result)) - KeyFunctions[RD] = const_cast<Decl *>(Result); + KeyFunctions[RD] = const_cast<Decl*>(Result); return cast_or_null<CXXMethodDecl>(Result); } @@ -3523,8 +3534,7 @@ void ASTContext::setNonKeyFunction(const CXXMethodDecl *Method) { auto I = Map.find(Method->getParent()); // If it's not cached, there's nothing to do. - if (I == Map.end()) - return; + if (I == Map.end()) return; // If it is cached, check whether it's the target method, and if so, // remove it from the cache. Note, the call to 'get' might invalidate @@ -3569,8 +3579,8 @@ uint64_t ASTContext::lookupFieldBitOffset(const ObjCInterfaceDecl *OID, // directly. unsigned Index = 0; - for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); IVD; - IVD = IVD->getNextIvar()) { + for (const ObjCIvarDecl *IVD = Container->all_declared_ivar_begin(); + IVD; IVD = IVD->getNextIvar()) { if (Ivar == IVD) break; ++Index; @@ -3589,7 +3599,7 @@ const ASTRecordLayout & ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const { // Retrieve the definition if (D->hasExternalLexicalStorage() && !D->getDefinition()) - getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl *>(D)); + getExternalSource()->CompleteType(const_cast<ObjCInterfaceDecl*>(D)); D = D->getDefinition(); assert(D && !D->isInvalidDecl() && D->isThisDeclarationADefinition() && "Invalid interface decl!"); @@ -3612,8 +3622,8 @@ ASTContext::getObjCLayout(const ObjCInterfaceDecl *D) const { return *NewEntry; } -static void PrintOffset(raw_ostream &OS, CharUnits Offset, - unsigned IndentLevel) { +static void PrintOffset(raw_ostream &OS, + CharUnits Offset, unsigned IndentLevel) { OS << llvm::format("%10" PRId64 " | ", (int64_t)Offset.getQuantity()); OS.indent(IndentLevel * 2); } @@ -3642,9 +3652,12 @@ static void PrintIndentNoOffset(raw_ostream &OS, unsigned IndentLevel) { } static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, - const ASTContext &C, CharUnits Offset, - unsigned IndentLevel, const char *Description, - bool PrintSizeInfo, bool IncludeVirtualBases) { + const ASTContext &C, + CharUnits Offset, + unsigned IndentLevel, + const char* Description, + bool PrintSizeInfo, + bool IncludeVirtualBases) { const ASTRecordLayout &Layout = C.getASTRecordLayout(RD); auto CXXRD = dyn_cast<CXXRecordDecl>(RD); @@ -3710,7 +3723,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, uint64_t LocalFieldOffsetInBits = Layout.getFieldOffset(Field->getFieldIndex()); CharUnits FieldOffset = - Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); + Offset + C.toCharUnitsFromBits(LocalFieldOffsetInBits); // Recursively dump fields of record type. if (auto RT = Field->getType()->getAs<RecordType>()) { @@ -3738,7 +3751,7 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, // Dump virtual bases. if (CXXRD && IncludeVirtualBases) { const ASTRecordLayout::VBaseOffsetsMapTy &VtorDisps = - Layout.getVBaseOffsetsMap(); + Layout.getVBaseOffsetsMap(); for (const CXXBaseSpecifier &Base : CXXRD->vbases()) { assert(Base.isVirtual() && "Found non-virtual class!"); @@ -3752,16 +3765,14 @@ static void DumpRecordLayout(raw_ostream &OS, const RecordDecl *RD, } DumpRecordLayout(OS, VBase, C, VBaseOffset, IndentLevel, - VBase == Layout.getPrimaryBase() - ? "(primary virtual base)" - : "(virtual base)", + VBase == Layout.getPrimaryBase() ? + "(primary virtual base)" : "(virtual base)", /*PrintSizeInfo=*/false, /*IncludeVirtualBases=*/false); } } - if (!PrintSizeInfo) - return; + if (!PrintSizeInfo) return; PrintIndentNoOffset(OS, IndentLevel - 1); OS << "[sizeof=" << Layout.getSize().getQuantity(); >From 93ee1ddbb3aafa431648b3179262afa479804dcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Thu, 13 Mar 2025 20:27:20 +0100 Subject: [PATCH 04/11] test(clang-cl): bitfield & struct padding --- clang/test/Driver/windows-Wpadded.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 clang/test/Driver/windows-Wpadded.cpp diff --git a/clang/test/Driver/windows-Wpadded.cpp b/clang/test/Driver/windows-Wpadded.cpp new file mode 100644 index 0000000000000..3babf6db39270 --- /dev/null +++ b/clang/test/Driver/windows-Wpadded.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s + +struct Foo { + int b : 1; + char a; +}; + +int main () {Foo foo;} + +// WARN: warning: padding struct 'Foo' with 31 bits to align 'a' +// WARN: warning: padding size of 'Foo' with 3 bytes to alignment boundary >From a259c2bb1b5a48d27a91f79e720dbec9d77e7585 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Tue, 18 Mar 2025 00:24:50 +0100 Subject: [PATCH 05/11] refacto: made CheckFieldPadding a static helper --- clang/lib/AST/RecordLayoutBuilder.cpp | 86 ++++++++------------------- 1 file changed, 24 insertions(+), 62 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 68d70ebadddcb..db4401650e2ef 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2274,9 +2274,10 @@ static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { } } -void ItaniumRecordLayoutBuilder::CheckFieldPadding( - uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset, - unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) { +// Function based on ItaniumRecordLayoutBuilder::CheckFieldPadding. +static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, + uint64_t Offset, uint64_t UnpaddedOffset, + const FieldDecl *D) { // We let objc ivars without warning, objc interfaces generally are not used // for padding tricks. if (isa<ObjCIvarDecl>(D)) @@ -2300,7 +2301,8 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding( if (D->getIdentifier()) { auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_bitfield : diag::warn_padded_struct_field; - Diag(D->getLocation(), Diagnostic) + Context.getDiagnostics().Report(D->getLocation(), + Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0) // (byte|bit) @@ -2308,15 +2310,22 @@ void ItaniumRecordLayoutBuilder::CheckFieldPadding( } else { auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_anon_bitfield : diag::warn_padded_struct_anon_field; - Diag(D->getLocation(), Diagnostic) + Context.getDiagnostics().Report(D->getLocation(), + Diagnostic) << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) << Context.getTypeDeclType(D->getParent()) << PadSize << (InBits ? 1 : 0); // (byte|bit) } - } - if (isPacked && Offset != UnpackedOffset) { - HasPackedField = true; - } + } +} + +void ItaniumRecordLayoutBuilder::CheckFieldPadding( + uint64_t Offset, uint64_t UnpaddedOffset, uint64_t UnpackedOffset, + unsigned UnpackedAlign, bool isPacked, const FieldDecl *D) { + ::CheckFieldPadding(Context, IsUnion, Offset, UnpaddedOffset, D); + if (isPacked && Offset != UnpackedOffset) { + HasPackedField = true; + } } static const CXXMethodDecl *computeKeyFunction(ASTContext &Context, @@ -2605,8 +2614,6 @@ struct MicrosoftRecordLayoutBuilder { void computeVtorDispSet( llvm::SmallPtrSetImpl<const CXXRecordDecl *> &HasVtorDispSet, const CXXRecordDecl *RD) const; - void CheckFieldPadding(uint64_t Offset, uint64_t UnpaddedOffset, - const FieldDecl *D); const ASTContext &Context; EmptySubobjectMap *EmptySubobjects; @@ -3008,8 +3015,8 @@ void MicrosoftRecordLayoutBuilder::layoutField(const FieldDecl *FD) { uint64_t UnpaddedFielddOffsetInBits = Context.toBits(DataSize) - RemainingBitsInField; - CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFielddOffsetInBits, - FD); + ::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset), + UnpaddedFielddOffsetInBits, FD); RemainingBitsInField = 0; @@ -3064,8 +3071,8 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { Size = FieldOffset + Info.Size; Alignment = std::max(Alignment, Info.Alignment); RemainingBitsInField = Context.toBits(Info.Size) - Width; - CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffsetInBits, - FD); + ::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset), + UnpaddedFieldOffsetInBits, FD); } DataSize = Size; } @@ -3095,8 +3102,8 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { RemainingBitsInField = 0; Size = FieldOffset; Alignment = std::max(Alignment, Info.Alignment); - CheckFieldPadding(Context.toBits(FieldOffset), UnpaddedFieldOffsetInBits, - FD); + ::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset), + UnpaddedFieldOffsetInBits, FD); } DataSize = Size; } @@ -3219,51 +3226,6 @@ void MicrosoftRecordLayoutBuilder::layoutVirtualBases(const CXXRecordDecl *RD) { PreviousBaseLayout = &BaseLayout; } } -// Function based on ItaniumRecordLayoutBuilder::CheckFieldPadding. -void MicrosoftRecordLayoutBuilder::CheckFieldPadding(uint64_t Offset, - uint64_t UnpaddedOffset, - const FieldDecl *D) { - - // We let objc ivars without warning, objc interfaces generally are not used - // for padding tricks. - if (isa<ObjCIvarDecl>(D)) - return; - - // Don't warn about structs created without a SourceLocation. This can - // be done by clients of the AST, such as codegen. - if (D->getLocation().isInvalid()) - return; - - unsigned CharBitNum = Context.getTargetInfo().getCharWidth(); - - // Warn if padding was introduced to the struct/class. - if (!IsUnion && Offset > UnpaddedOffset) { - unsigned PadSize = Offset - UnpaddedOffset; - bool InBits = true; - if (PadSize % CharBitNum == 0) { - PadSize = PadSize / CharBitNum; - InBits = false; - } - if (D->getIdentifier()) { - auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_bitfield - : diag::warn_padded_struct_field; - Context.getDiagnostics().Report(D->getLocation(), - Diagnostic) - << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize - << (InBits ? 1 : 0) // (byte|bit) - << D->getIdentifier(); - } else { - auto Diagnostic = D->isBitField() ? diag::warn_padded_struct_anon_bitfield - : diag::warn_padded_struct_anon_field; - Context.getDiagnostics().Report(D->getLocation(), - Diagnostic) - << getPaddingDiagFromTagKind(D->getParent()->getTagKind()) - << Context.getTypeDeclType(D->getParent()) << PadSize - << (InBits ? 1 : 0); // (byte|bit) - } - } -} void MicrosoftRecordLayoutBuilder::finalizeLayout(const RecordDecl *RD) { uint64_t UnpaddedSizeInBits = Context.toBits(DataSize); >From ec85ec2348ada4b561a47e8ffc832eeae1a544e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Tue, 18 Mar 2025 00:25:48 +0100 Subject: [PATCH 06/11] test(clang-cl): anonymous bitfield, union, alignas, derived padding --- clang/test/Driver/windows-Wpadded-alignas.cpp | 12 ++++++++++++ .../windows-Wpadded-anonymous-bitfield.cpp | 12 ++++++++++++ .../Driver/windows-Wpadded-derived-struct.cpp | 13 +++++++++++++ clang/test/Driver/windows-Wpadded-union.cpp | 19 +++++++++++++++++++ clang/test/Driver/windows-Wpadded.cpp | 3 ++- 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 clang/test/Driver/windows-Wpadded-alignas.cpp create mode 100644 clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp create mode 100644 clang/test/Driver/windows-Wpadded-derived-struct.cpp create mode 100644 clang/test/Driver/windows-Wpadded-union.cpp diff --git a/clang/test/Driver/windows-Wpadded-alignas.cpp b/clang/test/Driver/windows-Wpadded-alignas.cpp new file mode 100644 index 0000000000000..6160cd9b4a47b --- /dev/null +++ b/clang/test/Driver/windows-Wpadded-alignas.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s +// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s + +struct __attribute__((ms_struct)) AlignedStruct { + char c; + alignas(8) int i; +}; + +int main() {AlignedStruct s;} + +// WARN: warning: padding struct 'AlignedStruct' with 7 bytes to align 'i' +// WARN: warning: padding size of 'AlignedStruct' with 4 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp b/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp new file mode 100644 index 0000000000000..a16a84c4f7487 --- /dev/null +++ b/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp @@ -0,0 +1,12 @@ +// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s + +struct __attribute__((ms_struct)) BitfieldStruct { + char c : 1; + int : 0; + char i; +}; + +int main() {BitfieldStruct s;} + +// WARN: warning: padding struct 'BitfieldStruct' with 31 bits to align anonymous bit-field +// WARN: warning: padding size of 'BitfieldStruct' with 3 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-derived-struct.cpp b/clang/test/Driver/windows-Wpadded-derived-struct.cpp new file mode 100644 index 0000000000000..ae2325258770f --- /dev/null +++ b/clang/test/Driver/windows-Wpadded-derived-struct.cpp @@ -0,0 +1,13 @@ +// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s +// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s + +struct Base { + int b; +}; + +struct Derived : public Base { + char c; +}; + +int main() {Derived d;} +// WARN: warning: padding size of 'Derived' with 3 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-union.cpp b/clang/test/Driver/windows-Wpadded-union.cpp new file mode 100644 index 0000000000000..f5b591ea62ac8 --- /dev/null +++ b/clang/test/Driver/windows-Wpadded-union.cpp @@ -0,0 +1,19 @@ +// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s +// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s + +union __attribute__((ms_struct)) Union { + char c; + long long u; +}; + +struct __attribute__((ms_struct)) StructWithUnion { + char c; + int : 0; + Union t; + short i; +}; + +int main() { StructWithUnion s; } + +// WARN: warning: padding struct 'StructWithUnion' with 7 bytes to align 't' +// WARN: warning: padding size of 'StructWithUnion' with 6 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded.cpp b/clang/test/Driver/windows-Wpadded.cpp index 3babf6db39270..67bd5dc076637 100644 --- a/clang/test/Driver/windows-Wpadded.cpp +++ b/clang/test/Driver/windows-Wpadded.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s +// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s -struct Foo { +struct __attribute__((ms_struct)) Foo { int b : 1; char a; }; >From b969498abe3ff7449bec17118d3f56f77b532c17 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Tue, 18 Mar 2025 20:09:03 +0100 Subject: [PATCH 07/11] refacto: removed inaccurate comment --- clang/lib/AST/RecordLayoutBuilder.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index db4401650e2ef..65d7307135300 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -2274,7 +2274,6 @@ static unsigned getPaddingDiagFromTagKind(TagTypeKind Tag) { } } -// Function based on ItaniumRecordLayoutBuilder::CheckFieldPadding. static void CheckFieldPadding(const ASTContext &Context, bool IsUnion, uint64_t Offset, uint64_t UnpaddedOffset, const FieldDecl *D) { >From f722c6eb16f09919d1421e713c0280813d2002c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Wed, 19 Mar 2025 18:24:41 +0100 Subject: [PATCH 08/11] refacto(tests): moved folder and combined test files when possible --- clang/test/Driver/windows-Wpadded-alignas.cpp | 12 ------ .../windows-Wpadded-anonymous-bitfield.cpp | 12 ------ .../Driver/windows-Wpadded-derived-struct.cpp | 13 ------ clang/test/Driver/windows-Wpadded-union.cpp | 19 --------- clang/test/Driver/windows-Wpadded.cpp | 12 ------ .../test/SemaCXX/windows-Wpadded-bitfield.cpp | 11 +++++ clang/test/SemaCXX/windows-Wpadded.cpp | 40 +++++++++++++++++++ 7 files changed, 51 insertions(+), 68 deletions(-) delete mode 100644 clang/test/Driver/windows-Wpadded-alignas.cpp delete mode 100644 clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp delete mode 100644 clang/test/Driver/windows-Wpadded-derived-struct.cpp delete mode 100644 clang/test/Driver/windows-Wpadded-union.cpp delete mode 100644 clang/test/Driver/windows-Wpadded.cpp create mode 100644 clang/test/SemaCXX/windows-Wpadded-bitfield.cpp create mode 100644 clang/test/SemaCXX/windows-Wpadded.cpp diff --git a/clang/test/Driver/windows-Wpadded-alignas.cpp b/clang/test/Driver/windows-Wpadded-alignas.cpp deleted file mode 100644 index 6160cd9b4a47b..0000000000000 --- a/clang/test/Driver/windows-Wpadded-alignas.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s -// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s - -struct __attribute__((ms_struct)) AlignedStruct { - char c; - alignas(8) int i; -}; - -int main() {AlignedStruct s;} - -// WARN: warning: padding struct 'AlignedStruct' with 7 bytes to align 'i' -// WARN: warning: padding size of 'AlignedStruct' with 4 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp b/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp deleted file mode 100644 index a16a84c4f7487..0000000000000 --- a/clang/test/Driver/windows-Wpadded-anonymous-bitfield.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s - -struct __attribute__((ms_struct)) BitfieldStruct { - char c : 1; - int : 0; - char i; -}; - -int main() {BitfieldStruct s;} - -// WARN: warning: padding struct 'BitfieldStruct' with 31 bits to align anonymous bit-field -// WARN: warning: padding size of 'BitfieldStruct' with 3 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-derived-struct.cpp b/clang/test/Driver/windows-Wpadded-derived-struct.cpp deleted file mode 100644 index ae2325258770f..0000000000000 --- a/clang/test/Driver/windows-Wpadded-derived-struct.cpp +++ /dev/null @@ -1,13 +0,0 @@ -// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s -// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s - -struct Base { - int b; -}; - -struct Derived : public Base { - char c; -}; - -int main() {Derived d;} -// WARN: warning: padding size of 'Derived' with 3 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded-union.cpp b/clang/test/Driver/windows-Wpadded-union.cpp deleted file mode 100644 index f5b591ea62ac8..0000000000000 --- a/clang/test/Driver/windows-Wpadded-union.cpp +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s -// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s - -union __attribute__((ms_struct)) Union { - char c; - long long u; -}; - -struct __attribute__((ms_struct)) StructWithUnion { - char c; - int : 0; - Union t; - short i; -}; - -int main() { StructWithUnion s; } - -// WARN: warning: padding struct 'StructWithUnion' with 7 bytes to align 't' -// WARN: warning: padding size of 'StructWithUnion' with 6 bytes to alignment boundary diff --git a/clang/test/Driver/windows-Wpadded.cpp b/clang/test/Driver/windows-Wpadded.cpp deleted file mode 100644 index 67bd5dc076637..0000000000000 --- a/clang/test/Driver/windows-Wpadded.cpp +++ /dev/null @@ -1,12 +0,0 @@ -// RUN: %clang_cl -Wpadded -Wno-msvc-not-found -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s -// RUN: %clang -Wpadded -fsyntax-only -- %s 2>&1 | FileCheck -check-prefix=WARN %s - -struct __attribute__((ms_struct)) Foo { - int b : 1; - char a; -}; - -int main () {Foo foo;} - -// WARN: warning: padding struct 'Foo' with 31 bits to align 'a' -// WARN: warning: padding size of 'Foo' with 3 bytes to alignment boundary diff --git a/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp b/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp new file mode 100644 index 0000000000000..2907d0201d98d --- /dev/null +++ b/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -verify -Wpadded %s + +struct __attribute__((ms_struct)) BitfieldStruct { // expected-warning {{padding size of 'BitfieldStruct' with 3 bytes to alignment boundary}} + char c : 1; + int : 0; // expected-warning {{padding struct 'BitfieldStruct' with 31 bits to align anonymous bit-field}} + char i; +}; + +int main() { + BitfieldStruct b; +} diff --git a/clang/test/SemaCXX/windows-Wpadded.cpp b/clang/test/SemaCXX/windows-Wpadded.cpp new file mode 100644 index 0000000000000..da3f2bf08c6b8 --- /dev/null +++ b/clang/test/SemaCXX/windows-Wpadded.cpp @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-windows-msvc -fsyntax-only -verify -Wpadded %s +// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -Wpadded %s + +struct __attribute__((ms_struct)) Foo { // expected-warning {{padding size of 'Foo' with 3 bytes to alignment boundary}} + int b : 1; + char a; // expected-warning {{padding struct 'Foo' with 31 bits to align 'a'}} +}; + +struct __attribute__((ms_struct)) AlignedStruct { // expected-warning {{padding size of 'AlignedStruct' with 4 bytes to alignment boundary}} + char c; + alignas(8) int i; // expected-warning {{padding struct 'AlignedStruct' with 7 bytes to align 'i'}} +}; + + +struct Base { + int b; +}; + +struct Derived : public Base { // expected-warning {{padding size of 'Derived' with 3 bytes to alignment boundary}} + char c; +}; + +union __attribute__((ms_struct)) Union { + char c; + long long u; +}; + +struct __attribute__((ms_struct)) StructWithUnion { // expected-warning {{padding size of 'StructWithUnion' with 6 bytes to alignment boundary}} + char c; + int : 0; + Union t; // expected-warning {{padding struct 'StructWithUnion' with 7 bytes to align 't'}} + short i; +}; + +int main() { + Foo f; + AlignedStruct a; + Derived d; + StructWithUnion swu; +} >From 6c79da3341ee0cc6892d575568a29450cab8847d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Thu, 27 Mar 2025 18:28:06 +0100 Subject: [PATCH 09/11] test(clang-cl): more bitfield padding tests --- .../test/SemaCXX/windows-Wpadded-bitfield.cpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp b/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp index 2907d0201d98d..ee5a57124eca5 100644 --- a/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp +++ b/clang/test/SemaCXX/windows-Wpadded-bitfield.cpp @@ -6,6 +6,27 @@ struct __attribute__((ms_struct)) BitfieldStruct { // expected-warning {{padding char i; }; +struct __attribute__((ms_struct)) SevenBitfieldStruct { // expected-warning {{padding size of 'SevenBitfieldStruct' with 3 bytes to alignment boundary}} + char c : 7; + int : 0; // expected-warning {{padding struct 'SevenBitfieldStruct' with 25 bits to align anonymous bit-field}} + char i; +}; + +struct __attribute__((ms_struct)) SameUnitSizeBitfield { + char c : 7; + char : 1; // Same unit size attributes fall in the same unit + they fill the unit -> no padding + char i; +}; + +struct __attribute__((ms_struct)) DifferentUnitSizeBitfield { // expected-warning {{padding size of 'DifferentUnitSizeBitfield' with 3 bytes to alignment boundary}} + char c : 7; + int : 1; // expected-warning {{padding struct 'DifferentUnitSizeBitfield' with 25 bits to align anonymous bit-field}} + char i; // expected-warning {{padding struct 'DifferentUnitSizeBitfield' with 31 bits to align 'i'}} +}; + int main() { BitfieldStruct b; + SevenBitfieldStruct s; + SameUnitSizeBitfield su; + DifferentUnitSizeBitfield du; } >From ca615889b4ad7e400773f3e5a11f70befe42f7e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Fri, 28 Mar 2025 01:05:46 +0100 Subject: [PATCH 10/11] chore: clang-format --- clang/lib/AST/RecordLayoutBuilder.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/RecordLayoutBuilder.cpp b/clang/lib/AST/RecordLayoutBuilder.cpp index 65d7307135300..41e7198cb7581 100644 --- a/clang/lib/AST/RecordLayoutBuilder.cpp +++ b/clang/lib/AST/RecordLayoutBuilder.cpp @@ -3071,7 +3071,7 @@ void MicrosoftRecordLayoutBuilder::layoutBitField(const FieldDecl *FD) { Alignment = std::max(Alignment, Info.Alignment); RemainingBitsInField = Context.toBits(Info.Size) - Width; ::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset), - UnpaddedFieldOffsetInBits, FD); + UnpaddedFieldOffsetInBits, FD); } DataSize = Size; } @@ -3102,7 +3102,7 @@ MicrosoftRecordLayoutBuilder::layoutZeroWidthBitField(const FieldDecl *FD) { Size = FieldOffset; Alignment = std::max(Alignment, Info.Alignment); ::CheckFieldPadding(Context, IsUnion, Context.toBits(FieldOffset), - UnpaddedFieldOffsetInBits, FD); + UnpaddedFieldOffsetInBits, FD); } DataSize = Size; } >From 721da29ecb1529d81b2c839c25151cf0c9f9ab82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20De=20Magalhaes?= <theo.de-magalh...@epita.fr> Date: Fri, 28 Mar 2025 18:47:37 +0100 Subject: [PATCH 11/11] chore: updated clang release notes --- clang/docs/ReleaseNotes.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index eaecead0e6b9d..d2f23f05e7631 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -187,6 +187,8 @@ Modified Compiler Flags - The compiler flag `-fbracket-depth` default value is increased from 256 to 2048. (#GH94728) +- `-Wpadded` option implemented for the `x86_64-windows-msvc` target. Fixes #61702 + Removed Compiler Flags ------------------------- _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits