Index: clang/include/clang/AST/DeclarationName.h =================================================================== --- clang/include/clang/AST/DeclarationName.h +++ clang/include/clang/AST/DeclarationName.h @@ -21,6 +21,7 @@ #include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/FoldingSet.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/type_traits.h" #include @@ -192,6 +193,13 @@ "The various classes that DeclarationName::Ptr can point to" " must be at least aligned to 8 bytes!"); + static_assert( + std::is_same, + std::underlying_type_t< + detail::DeclarationNameExtra::ExtraKind>>::value, + "The various enums used to compute values for NameKind should " + "all have the same underlying type"); + public: /// The kind of the name stored in this DeclarationName. /// The first 7 enumeration values are stored inline and correspond @@ -205,15 +213,18 @@ CXXDestructorName = StoredCXXDestructorName, CXXConversionFunctionName = StoredCXXConversionFunctionName, CXXOperatorName = StoredCXXOperatorName, - CXXDeductionGuideName = UncommonNameKindOffset + - detail::DeclarationNameExtra::CXXDeductionGuideName, - CXXLiteralOperatorName = - UncommonNameKindOffset + - detail::DeclarationNameExtra::CXXLiteralOperatorName, - CXXUsingDirective = UncommonNameKindOffset + - detail::DeclarationNameExtra::CXXUsingDirective, - ObjCMultiArgSelector = UncommonNameKindOffset + - detail::DeclarationNameExtra::ObjCMultiArgSelector + CXXDeductionGuideName = llvm::addEnumValues( + UncommonNameKindOffset, + detail::DeclarationNameExtra::CXXDeductionGuideName), + CXXLiteralOperatorName = llvm::addEnumValues( + UncommonNameKindOffset, + detail::DeclarationNameExtra::CXXLiteralOperatorName), + CXXUsingDirective = + llvm::addEnumValues(UncommonNameKindOffset, + detail::DeclarationNameExtra::CXXUsingDirective), + ObjCMultiArgSelector = + llvm::addEnumValues(UncommonNameKindOffset, + detail::DeclarationNameExtra::ObjCMultiArgSelector), }; private: Index: llvm/include/llvm/ADT/STLExtras.h =================================================================== --- llvm/include/llvm/ADT/STLExtras.h +++ llvm/include/llvm/ADT/STLExtras.h @@ -203,6 +203,17 @@ template using TypeAtIndex = std::tuple_element_t>; +/// Helper which adds two underlying types of enumeration type. +/// Implicit conversion to a common type is accepted. +template ::value, + std::underlying_type_t>, + typename UT2 = std::enable_if_t::value, + std::underlying_type_t>> +constexpr auto addEnumValues(EnumTy1 LHS, EnumTy2 RHS) { + return static_cast(LHS) + static_cast(RHS); +} + //===----------------------------------------------------------------------===// // Extra additions to //===----------------------------------------------------------------------===// Index: llvm/unittests/ADT/STLExtrasTest.cpp =================================================================== --- llvm/unittests/ADT/STLExtrasTest.cpp +++ llvm/unittests/ADT/STLExtrasTest.cpp @@ -9,6 +9,7 @@ #include "llvm/ADT/STLExtras.h" #include "gtest/gtest.h" +#include #include #include @@ -989,4 +990,32 @@ static_assert(!is_contained({1, 2, 3, 4}, 5), "It's not there :("); } +TEST(STLExtrasTest, addEnumValues) { + enum A { Zero = 0, One = 1 }; + enum B { IntMax = INT_MAX, ULongLongMax = ULLONG_MAX }; + enum class C : unsigned { Two = 2 }; + + // Non-fixed underlying types, with same underlying types + static_assert(addEnumValues(Zero, One) == 1, + "addEnumValues(Zero, One) failed."); + static_assert(addEnumValues(IntMax, ULongLongMax) == + INT_MAX + static_cast(ULLONG_MAX), + "addEnumValues(IntMax, ULongLongMax) failed."); + // Non-fixed underlying types, with different underlying types + static_assert(addEnumValues(Zero, IntMax) == INT_MAX, + "addEnumValues(Zero, IntMax) failed."); + static_assert(addEnumValues(One, ULongLongMax) == + 1 + static_cast(ULLONG_MAX), + "addEnumValues(One, ULongLongMax) failed."); + // Non-fixed underlying type enum and fixed underlying type enum, with same + // underlying types + static_assert(addEnumValues(One, C::Two) == 3, + "addEnumValues(One, C::Two) failed."); + // Non-fixed underlying type enum and fixed underlying type enum, with + // different underlying types + static_assert(addEnumValues(ULongLongMax, C::Two) == + static_cast(ULLONG_MAX) + 2, + "addEnumValues(ULongLongMax, C::Two) failed."); +} + } // namespace