diff --git a/clang/include/clang/AST/DeclBase.h b/clang/include/clang/AST/DeclBase.h --- a/clang/include/clang/AST/DeclBase.h +++ b/clang/include/clang/AST/DeclBase.h @@ -20,6 +20,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" +#include "clang/Support/BitFieldReflection.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/PointerUnion.h" @@ -1420,6 +1421,18 @@ /// hasLazyLocalLexicalLookups, hasLazyExternalLexicalLookups friend class ASTWriter; +#define BITSOF_FIELD(CLASS, FIELD) \ + BitFieldReflector::countBits( \ + BitFieldReflector::instanceOf() \ + .FIELD) +#define STATIC_ASSERT_BITFIELDS(CLASS, BITS, FIELDS) \ + static_assert( \ + Num##CLASS##Bits == BITS && \ + BitFieldReflector::FieldCounter::value == FIELDS, \ + "You need to update Num" #CLASS \ + "Bits or number of fields after changing " #CLASS "Bitfields!") + // We use uint64_t in the bit-fields below since some bit-fields // cross the unsigned boundary and this breaks the packing. @@ -1427,6 +1440,7 @@ /// If modified NumDeclContextBit, the ctor of DeclContext and the accessor /// methods in DeclContext should be updated appropriately. class DeclContextBitfields { + public: friend class DeclContext; /// DeclKind - This indicates which class this is. uint64_t DeclKind : 7; @@ -1461,13 +1475,23 @@ mutable uint64_t UseQualifiedLookup : 1; }; +#define BITSOF(FIELD) BITSOF_FIELD(DeclContext, FIELD) /// Number of bits in DeclContextBitfields. - enum { NumDeclContextBits = 13 }; + enum { + NumDeclContextBits = BITSOF(DeclKind) + BITSOF(ExternalLexicalStorage) + + BITSOF(ExternalVisibleStorage) + + BITSOF(NeedToReconcileExternalVisibleStorage) + + BITSOF(HasLazyLocalLexicalLookups) + + BITSOF(HasLazyExternalLexicalLookups) + + BITSOF(UseQualifiedLookup) + }; + STATIC_ASSERT_BITFIELDS(DeclContext, 13, 7); /// Stores the bits used by TagDecl. /// If modified NumTagDeclBits and the accessor /// methods in TagDecl should be updated appropriately. class TagDeclBitfields { + public: friend class TagDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; @@ -1505,13 +1529,23 @@ uint64_t IsThisDeclarationADemotedDefinition : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(TagDecl, FIELD) /// Number of non-inherited bits in TagDeclBitfields. - enum { NumTagDeclBits = 10 }; + enum { + NumTagDeclBits = BITSOF(TagDeclKind) + BITSOF(IsCompleteDefinition) + + BITSOF(IsBeingDefined) + BITSOF(IsEmbeddedInDeclarator) + + BITSOF(IsFreeStanding) + BITSOF(MayHaveOutOfDateDef) + + BITSOF(IsCompleteDefinitionRequired) + + BITSOF(IsThisDeclarationADemotedDefinition) + }; + STATIC_ASSERT_BITFIELDS(TagDecl, 10, 8); /// Stores the bits used by EnumDecl. /// If modified NumEnumDeclBit and the accessor /// methods in EnumDecl should be updated appropriately. class EnumDeclBitfields { + public: friend class EnumDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; @@ -1544,13 +1578,21 @@ uint64_t HasODRHash : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(EnumDecl, FIELD) /// Number of non-inherited bits in EnumDeclBitfields. - enum { NumEnumDeclBits = 20 }; + enum { + NumEnumDeclBits = BITSOF(NumPositiveBits) + BITSOF(NumNegativeBits) + + BITSOF(IsScoped) + BITSOF(IsScopedUsingClassTag) + + BITSOF(IsFixed) + BITSOF(HasODRHash) + }; + STATIC_ASSERT_BITFIELDS(EnumDecl, 20, 6); /// Stores the bits used by RecordDecl. /// If modified NumRecordDeclBits and the accessor /// methods in RecordDecl should be updated appropriately. class RecordDeclBitfields { + public: friend class RecordDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; @@ -1605,13 +1647,30 @@ uint64_t ODRHash : 26; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(RecordDecl, FIELD) /// Number of non-inherited bits in RecordDeclBitfields. - enum { NumRecordDeclBits = 41 }; + enum { + NumRecordDeclBits = + BITSOF(HasFlexibleArrayMember) + BITSOF(AnonymousStructOrUnion) + + BITSOF(HasObjectMember) + BITSOF(HasVolatileMember) + + BITSOF(LoadedFieldsFromExternalStorage) + + BITSOF(NonTrivialToPrimitiveDefaultInitialize) + + BITSOF(NonTrivialToPrimitiveCopy) + + BITSOF(NonTrivialToPrimitiveDestroy) + + BITSOF(HasNonTrivialToPrimitiveDefaultInitializeCUnion) + + BITSOF(HasNonTrivialToPrimitiveDestructCUnion) + + BITSOF(HasNonTrivialToPrimitiveCopyCUnion) + + BITSOF(ParamDestroyedInCallee) + BITSOF(ArgPassingRestrictions) + + BITSOF(IsRandomized) + BITSOF(ODRHash) + }; + STATIC_ASSERT_BITFIELDS(RecordDecl, 41, 15); /// Stores the bits used by OMPDeclareReductionDecl. /// If modified NumOMPDeclareReductionDeclBits and the accessor /// methods in OMPDeclareReductionDecl should be updated appropriately. class OMPDeclareReductionDeclBitfields { + public: friend class OMPDeclareReductionDecl; /// For the bits in DeclContextBitfields uint64_t : NumDeclContextBits; @@ -1621,14 +1680,18 @@ uint64_t InitializerKind : 2; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(OMPDeclareReductionDecl, FIELD) /// Number of non-inherited bits in OMPDeclareReductionDeclBitfields. - enum { NumOMPDeclareReductionDeclBits = 2 }; + enum { NumOMPDeclareReductionDeclBits = BITSOF(InitializerKind) }; + STATIC_ASSERT_BITFIELDS(OMPDeclareReductionDecl, 2, 1); /// Stores the bits used by FunctionDecl. /// If modified NumFunctionDeclBits and the accessor /// methods in FunctionDecl and CXXDeductionGuideDecl /// (for DeductionCandidateKind) should be updated appropriately. class FunctionDeclBitfields { + public: friend class FunctionDecl; /// For DeductionCandidateKind friend class CXXDeductionGuideDecl; @@ -1701,13 +1764,32 @@ uint64_t FriendConstraintRefersToEnclosingTemplate : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(FunctionDecl, FIELD) /// Number of non-inherited bits in FunctionDeclBitfields. - enum { NumFunctionDeclBits = 31 }; + enum { + NumFunctionDeclBits = + BITSOF(SClass) + BITSOF(IsInline) + BITSOF(IsInlineSpecified) + + BITSOF(IsVirtualAsWritten) + BITSOF(IsPure) + + BITSOF(HasInheritedPrototype) + BITSOF(HasWrittenPrototype) + + BITSOF(IsDeleted) + BITSOF(IsTrivial) + BITSOF(IsTrivialForCall) + + BITSOF(IsDefaulted) + BITSOF(IsExplicitlyDefaulted) + + BITSOF(HasDefaultedFunctionInfo) + BITSOF(IsIneligibleOrNotSelected) + + BITSOF(HasImplicitReturnZero) + BITSOF(IsLateTemplateParsed) + + BITSOF(ConstexprKind) + + BITSOF(BodyContainsImmediateEscalatingExpression) + + BITSOF(InstantiationIsPending) + BITSOF(UsesSEHTry) + + BITSOF(HasSkippedBody) + BITSOF(WillHaveBody) + BITSOF(IsMultiVersion) + + BITSOF(DeductionCandidateKind) + BITSOF(HasODRHash) + + BITSOF(UsesFPIntrin) + BITSOF(FriendConstraintRefersToEnclosingTemplate) + }; + STATIC_ASSERT_BITFIELDS(FunctionDecl, 31, 27); /// Stores the bits used by CXXConstructorDecl. If modified /// NumCXXConstructorDeclBits and the accessor /// methods in CXXConstructorDecl should be updated appropriately. class CXXConstructorDeclBitfields { + public: friend class CXXConstructorDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; @@ -1729,15 +1811,27 @@ uint64_t IsSimpleExplicit : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(CXXConstructorDecl, FIELD) /// Number of non-inherited bits in CXXConstructorDeclBitfields. enum { - NumCXXConstructorDeclBits = 64 - NumDeclContextBits - NumFunctionDeclBits + NumCXXConstructorDeclBits = + BITSOF(NumCtorInitializers) + BITSOF(IsInheritingConstructor) + + BITSOF(HasTrailingExplicitSpecifier) + BITSOF(IsSimpleExplicit) }; + STATIC_ASSERT_BITFIELDS(CXXConstructorDecl, 20, 4); + + static_assert(NumDeclContextBits + NumFunctionDeclBits + + NumCXXConstructorDeclBits == + 64, + "You need to update NumCtorInitializers so that " + "CXXConstructorDeclBitfields take exactly 64 bits!"); /// Stores the bits used by ObjCMethodDecl. /// If modified NumObjCMethodDeclBits and the accessor /// methods in ObjCMethodDecl should be updated appropriately. class ObjCMethodDeclBitfields { + public: friend class ObjCMethodDecl; /// For the bits in DeclContextBitfields. @@ -1793,8 +1887,19 @@ uint64_t HasSkippedBody : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(ObjCMethodDecl, FIELD) /// Number of non-inherited bits in ObjCMethodDeclBitfields. - enum { NumObjCMethodDeclBits = 24 }; + enum { + NumObjCMethodDeclBits = + BITSOF(Family) + BITSOF(IsInstance) + BITSOF(IsVariadic) + + BITSOF(IsPropertyAccessor) + BITSOF(IsSynthesizedAccessorStub) + + BITSOF(IsDefined) + BITSOF(IsRedeclaration) + BITSOF(HasRedeclaration) + + BITSOF(DeclImplementation) + BITSOF(objcDeclQualifier) + + BITSOF(RelatedResultType) + BITSOF(SelLocsKind) + BITSOF(IsOverriding) + + BITSOF(HasSkippedBody) + }; + STATIC_ASSERT_BITFIELDS(ObjCMethodDecl, 25, 14); /// Stores the bits used by ObjCContainerDecl. /// If modified NumObjCContainerDeclBits and the accessor @@ -1818,6 +1923,7 @@ /// If modified NumLinkageSpecDeclBits and the accessor /// methods in LinkageSpecDecl should be updated appropriately. class LinkageSpecDeclBitfields { + public: friend class LinkageSpecDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; @@ -1833,13 +1939,17 @@ uint64_t HasBraces : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(LinkageSpecDecl, FIELD) /// Number of non-inherited bits in LinkageSpecDeclBitfields. - enum { NumLinkageSpecDeclBits = 4 }; + enum { NumLinkageSpecDeclBits = BITSOF(Language) + BITSOF(HasBraces) }; + STATIC_ASSERT_BITFIELDS(LinkageSpecDecl, 4, 2); /// Stores the bits used by BlockDecl. /// If modified NumBlockDeclBits and the accessor /// methods in BlockDecl should be updated appropriately. class BlockDeclBitfields { + public: friend class BlockDecl; /// For the bits in DeclContextBitfields. uint64_t : NumDeclContextBits; @@ -1859,8 +1969,20 @@ uint64_t CanAvoidCopyToHeap : 1; }; +#undef BITSOF +#define BITSOF(FIELD) BITSOF_FIELD(BlockDecl, FIELD) /// Number of non-inherited bits in BlockDeclBitfields. - enum { NumBlockDeclBits = 5 }; + enum { + NumBlockDeclBits = BITSOF(IsVariadic) + BITSOF(CapturesCXXThis) + + BITSOF(BlockMissingReturnType) + + BITSOF(IsConversionFromLambda) + BITSOF(DoesNotEscape) + + BITSOF(CanAvoidCopyToHeap) + }; + STATIC_ASSERT_BITFIELDS(BlockDecl, 6, 6); + +#undef BITSOF +#undef BITSOF_FIELD +#undef STATIC_ASSERT_BITFIELDS /// Pointer to the data structure used to lookup declarations /// within this context (or a DependentStoredDeclsMap if this is a diff --git a/clang/include/clang/Support/BitFieldReflection.h b/clang/include/clang/Support/BitFieldReflection.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Support/BitFieldReflection.h @@ -0,0 +1,104 @@ +//===------- BitFieldReflection.h - BitField Reflection Utils ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines simple reflection utility for bit-fields. +// +//===----------------------------------------------------------------------===// + +#ifndef CLANG_SUPPORT_BIT_FIELD_REFLECTION_H +#define CLANG_SUPPORT_BIT_FIELD_REFLECTION_H + +#include +#include +#include + +#ifdef __clang__ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wbitfield-constant-conversion" +#pragma clang diagnostic ignored "-Wmissing-field-initializers" +#elif defined __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" +#pragma GCC diagnostic ignored "-Woverflow" +#endif + +namespace clang { + +class BitFieldReflector { +public: + template + static constexpr auto countBits(FieldT F, size_t StartBit = 0) -> + typename std::enable_if::value, size_t>::type { + return (StartBit == sizeof(FieldT) * 8) + ? 0 + : (countBits(F, StartBit + 1) + + ((F & (1ULL << StartBit)) ? 1 : 0)); + } + + template + static constexpr StructT instanceOf() { + static_assert(std::is_unsigned::value, + "Bit field is not unsigned!"); + return instanceOfImpl(StructT{}, 0); + } + +private: + template + static constexpr StructT instanceOfImpl(StructT S, ...) { + return S; + } + + template + static constexpr StructT instanceOfImpl(StructT S, decltype(StructT{Inits...}, + int()) = 0) { + return instanceOfImpl(-1)>( + StructT{Inits...}, 0); + } + +private: + struct is_implicitly_convertible { + template constexpr operator T() const; + }; + + template + struct is_initializable_ : std::false_type {}; + + template + struct is_initializable_()}...})>, + T, From...> : std::true_type {}; + + template + using is_initializable = is_initializable_, T, From...>; + + template + static constexpr size_t countFields(std::false_type) { + return sizeof...(Args) ? sizeof...(Args) - 1 : 0; + } + + template + static constexpr size_t countFields(std::true_type) { + return countFields( + is_initializable()); + } + +public: + template + struct FieldCounter + : public std::integral_constant(is_initializable())> {}; +}; + +} // namespace clang + +#ifdef __clang__ +#pragma clang diagnostic pop +#elif defined __GNUC__ +#pragma GCC diagnostic pop +#endif + +#endif // CLANG_SUPPORT_BIT_FIELD_REFLECTION_H diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -433,10 +433,6 @@ } void ASTDeclWriter::VisitTagDecl(TagDecl *D) { - static_assert(DeclContext::NumTagDeclBits == 10, - "You need to update the serializer after you change the " - "TagDeclBits"); - VisitRedeclarable(D); VisitTypeDecl(D); Record.push_back(D->getIdentifierNamespace()); @@ -461,10 +457,6 @@ } void ASTDeclWriter::VisitEnumDecl(EnumDecl *D) { - static_assert(DeclContext::NumEnumDeclBits == 20, - "You need to update the serializer after you change the " - "EnumDeclBits"); - VisitTagDecl(D); Record.AddTypeSourceInfo(D->getIntegerTypeSourceInfo()); if (!D->getIntegerTypeSourceInfo()) @@ -508,10 +500,6 @@ } void ASTDeclWriter::VisitRecordDecl(RecordDecl *D) { - static_assert(DeclContext::NumRecordDeclBits == 41, - "You need to update the serializer after you change the " - "RecordDeclBits"); - VisitTagDecl(D); Record.push_back(D->hasFlexibleArrayMember()); Record.push_back(D->isAnonymousStructOrUnion()); @@ -580,10 +568,6 @@ } void ASTDeclWriter::VisitFunctionDecl(FunctionDecl *D) { - static_assert(DeclContext::NumFunctionDeclBits == 31, - "You need to update the serializer after you change the " - "FunctionDeclBits"); - VisitRedeclarable(D); Record.push_back(D->getTemplatedKind()); @@ -735,10 +719,6 @@ } void ASTDeclWriter::VisitObjCMethodDecl(ObjCMethodDecl *D) { - static_assert(DeclContext::NumObjCMethodDeclBits == 24, - "You need to update the serializer after you change the " - "ObjCMethodDeclBits"); - VisitNamedDecl(D); // FIXME: convert to LazyStmtPtr? // Unlike C/C++, method bodies will never be in header files. @@ -797,10 +777,6 @@ } void ASTDeclWriter::VisitObjCContainerDecl(ObjCContainerDecl *D) { - static_assert(DeclContext::NumObjCContainerDeclBits == 51, - "You need to update the serializer after you change the " - "ObjCContainerDeclBits"); - VisitNamedDecl(D); Record.AddSourceLocation(D->getAtStartLoc()); Record.AddSourceRange(D->getAtEndRange()); @@ -1284,10 +1260,6 @@ } void ASTDeclWriter::VisitLinkageSpecDecl(LinkageSpecDecl *D) { - static_assert(DeclContext::NumLinkageSpecDeclBits == 4, - "You need to update the serializer after you change the" - "LinkageSpecDeclBits"); - VisitDecl(D); Record.push_back(D->getLanguage()); Record.AddSourceLocation(D->getExternLoc()); @@ -1495,10 +1467,6 @@ } void ASTDeclWriter::VisitCXXConstructorDecl(CXXConstructorDecl *D) { - static_assert(DeclContext::NumCXXConstructorDeclBits == 20, - "You need to update the serializer after you change the " - "CXXConstructorDeclBits"); - Record.push_back(D->getTrailingAllocKind()); addExplicitSpecifier(D->getExplicitSpecifier(), Record); if (auto Inherited = D->getInheritedConstructor()) { @@ -1875,10 +1843,6 @@ /// Emit the DeclContext part of a declaration context decl. void ASTDeclWriter::VisitDeclContext(DeclContext *DC) { - static_assert(DeclContext::NumDeclContextBits == 13, - "You need to update the serializer after you change the " - "DeclContextBits"); - Record.AddOffset(Writer.WriteDeclContextLexicalBlock(Context, DC)); Record.AddOffset(Writer.WriteDeclContextVisibleBlock(Context, DC)); } @@ -1989,10 +1953,6 @@ } void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { - static_assert(DeclContext::NumOMPDeclareReductionDeclBits == 2, - "You need to update the serializer after you change the " - "NumOMPDeclareReductionDeclBits"); - VisitValueDecl(D); Record.AddSourceLocation(D->getBeginLoc()); Record.AddStmt(D->getCombinerIn());