[Lldb-commits] [clang] [lldb] [lldb] Analyze enum promotion type during parsing (PR #115005)

Ilia Kuklin via lldb-commits lldb-commits at lists.llvm.org
Sat Feb 8 07:55:22 PST 2025


https://github.com/kuilpd updated https://github.com/llvm/llvm-project/pull/115005

>From 4d797371598960baf7729d05590aa1a8c7077694 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 01/13] [lldb] Analyze enum promotion type during parsing

---
 clang/include/clang/AST/Decl.h                |  2 +-
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 95 ++++++++++++++++++-
 .../TypeSystem/Clang/TypeSystemClang.cpp      | 26 +----
 3 files changed, 98 insertions(+), 25 deletions(-)

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 16403774e72b31c..41cb47516f58033 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3903,6 +3903,7 @@ class EnumDecl : public TagDecl {
   void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
                                     TemplateSpecializationKind TSK);
 
+public:
   /// Sets the width in bits required to store all the
   /// non-negative enumerators of this enum.
   void setNumPositiveBits(unsigned Num) {
@@ -3914,7 +3915,6 @@ class EnumDecl : public TagDecl {
   /// negative enumerators of this enum. (see getNumNegativeBits)
   void setNumNegativeBits(unsigned Num) { EnumDeclBits.NumNegativeBits = Num; }
 
-public:
   /// True if this tag declaration is a scoped enumeration. Only
   /// possible in C++11 mode.
   void setScoped(bool Scoped = true) { EnumDeclBits.IsScoped = Scoped; }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index e77188bfbd2e4a5..bb9c35a235c1ff4 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2316,6 +2316,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     return 0;
 
   size_t enumerators_added = 0;
+  unsigned NumNegativeBits = 0;
+  unsigned NumPositiveBits = 0;
 
   for (DWARFDIE die : parent_die.children()) {
     const dw_tag_t tag = die.Tag();
@@ -2367,11 +2369,102 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     }
 
     if (name && name[0] && got_value) {
-      m_ast.AddEnumerationValueToEnumerationType(
+      auto ECD = m_ast.AddEnumerationValueToEnumerationType(
           clang_type, decl, name, enum_value, enumerator_byte_size * 8);
       ++enumerators_added;
+
+      llvm::APSInt InitVal = ECD->getInitVal();
+      // Keep track of the size of positive and negative values.
+      if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
+        // If the enumerator is zero that should still be counted as a positive
+        // bit since we need a bit to store the value zero.
+        unsigned ActiveBits = InitVal.getActiveBits();
+        NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+      } else {
+        NumNegativeBits =
+            std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
+      }
     }
   }
+
+  /// The following code follows the same logic as in Sema::ActOnEnumBody
+  /// clang/lib/Sema/SemaDecl.cpp
+  // If we have an empty set of enumerators we still need one bit.
+  // From [dcl.enum]p8
+  // If the enumerator-list is empty, the values of the enumeration are as if
+  // the enumeration had a single enumerator with value 0
+  if (!NumPositiveBits && !NumNegativeBits)
+    NumPositiveBits = 1;
+
+  clang::QualType qual_type(ClangUtil::GetQualType(clang_type));
+  clang::EnumDecl *enum_decl = qual_type->getAs<clang::EnumType>()->getDecl();
+  enum_decl->setNumPositiveBits(NumPositiveBits);
+  enum_decl->setNumNegativeBits(NumNegativeBits);
+
+  // C++0x N3000 [conv.prom]p3:
+  //   An rvalue of an unscoped enumeration type whose underlying
+  //   type is not fixed can be converted to an rvalue of the first
+  //   of the following types that can represent all the values of
+  //   the enumeration: int, unsigned int, long int, unsigned long
+  //   int, long long int, or unsigned long long int.
+  // C99 6.4.4.3p2:
+  //   An identifier declared as an enumeration constant has type int.
+  // The C99 rule is modified by C23.
+  clang::QualType BestPromotionType;
+  unsigned BestWidth;
+
+  auto &Context = m_ast.getASTContext();
+  unsigned LongWidth = Context.getTargetInfo().getLongWidth();
+  unsigned IntWidth = Context.getTargetInfo().getIntWidth();
+  unsigned CharWidth = Context.getTargetInfo().getCharWidth();
+  unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
+
+  bool is_cpp = Language::LanguageIsCPlusPlus(
+      SymbolFileDWARF::GetLanguage(*parent_die.GetCU()));
+
+  if (NumNegativeBits) {
+    // If there is a negative value, figure out the smallest integer type (of
+    // int/long/longlong) that fits.
+    if (NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
+      BestWidth = CharWidth;
+    } else if (NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) {
+      BestWidth = ShortWidth;
+    } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+      BestWidth = IntWidth;
+    } else if (NumNegativeBits <= LongWidth && NumPositiveBits < LongWidth) {
+      BestWidth = LongWidth;
+    } else {
+      BestWidth = Context.getTargetInfo().getLongLongWidth();
+    }
+    BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : qual_type);
+  } else {
+    // If there is no negative value, figure out the smallest type that fits
+    // all of the enumerator values.
+    if (NumPositiveBits <= CharWidth) {
+      BestPromotionType = Context.IntTy;
+      BestWidth = CharWidth;
+    } else if (NumPositiveBits <= ShortWidth) {
+      BestPromotionType = Context.IntTy;
+      BestWidth = ShortWidth;
+    } else if (NumPositiveBits <= IntWidth) {
+      BestWidth = IntWidth;
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedIntTy
+                              : Context.IntTy;
+    } else if (NumPositiveBits <= LongWidth) {
+      BestWidth = LongWidth;
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedLongTy
+                              : Context.LongTy;
+    } else {
+      BestWidth = Context.getTargetInfo().getLongLongWidth();
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedLongLongTy
+                              : Context.LongLongTy;
+    }
+  }
+  enum_decl->setPromotionType(BestPromotionType);
+
   return enumerators_added;
 }
 
diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
index 47051f2e68090fc..94f99a8e360ee73 100644
--- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -2321,7 +2321,6 @@ CompilerType TypeSystemClang::CreateEnumerationType(
   if (decl_ctx)
     decl_ctx->addDecl(enum_decl);
 
-  // TODO: check if we should be setting the promotion type too?
   enum_decl->setIntegerType(ClangUtil::GetQualType(integer_clang_type));
 
   enum_decl->setAccess(AS_public); // TODO respect what's in the debug info
@@ -8453,30 +8452,11 @@ bool TypeSystemClang::CompleteTagDeclarationDefinition(
   if (enum_decl->isCompleteDefinition())
     return true;
 
-  clang::ASTContext &ast = lldb_ast->getASTContext();
-
-  /// TODO This really needs to be fixed.
-
   QualType integer_type(enum_decl->getIntegerType());
   if (!integer_type.isNull()) {
-    unsigned NumPositiveBits = 1;
-    unsigned NumNegativeBits = 0;
-
-    clang::QualType promotion_qual_type;
-    // If the enum integer type is less than an integer in bit width,
-    // then we must promote it to an integer size.
-    if (ast.getTypeSize(enum_decl->getIntegerType()) <
-        ast.getTypeSize(ast.IntTy)) {
-      if (enum_decl->getIntegerType()->isSignedIntegerType())
-        promotion_qual_type = ast.IntTy;
-      else
-        promotion_qual_type = ast.UnsignedIntTy;
-    } else
-      promotion_qual_type = enum_decl->getIntegerType();
-
-    enum_decl->completeDefinition(enum_decl->getIntegerType(),
-                                  promotion_qual_type, NumPositiveBits,
-                                  NumNegativeBits);
+    enum_decl->completeDefinition(
+        enum_decl->getIntegerType(), enum_decl->getPromotionType(),
+        enum_decl->getNumPositiveBits(), enum_decl->getNumNegativeBits());
   }
   return true;
 }

>From 1ba943dd5538b1d21552df151ac107451081aa17 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Tue, 5 Nov 2024 19:18:41 +0500
Subject: [PATCH 02/13] Fix enum's underlying type retrieval

---
 .../Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp       | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index bb9c35a235c1ff4..676cc7d7603655e 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2396,8 +2396,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   if (!NumPositiveBits && !NumNegativeBits)
     NumPositiveBits = 1;
 
-  clang::QualType qual_type(ClangUtil::GetQualType(clang_type));
-  clang::EnumDecl *enum_decl = qual_type->getAs<clang::EnumType>()->getDecl();
+  clang::EnumDecl *enum_decl =
+      ClangUtil::GetQualType(clang_type)->getAs<clang::EnumType>()->getDecl();
   enum_decl->setNumPositiveBits(NumPositiveBits);
   enum_decl->setNumNegativeBits(NumNegativeBits);
 
@@ -2436,7 +2436,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     } else {
       BestWidth = Context.getTargetInfo().getLongLongWidth();
     }
-    BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : qual_type);
+    BestPromotionType =
+        BestWidth <= IntWidth ? Context.IntTy : enum_decl->getIntegerType();
   } else {
     // If there is no negative value, figure out the smallest type that fits
     // all of the enumerator values.

>From c528dd54489be9e7617d14696a6bd79da87c06e8 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Tue, 5 Nov 2024 19:19:14 +0500
Subject: [PATCH 03/13] Add a test

---
 .../test/API/lang/cpp/enum_promotion/Makefile |  3 ++
 .../enum_promotion/TestCPPEnumPromotion.py    | 37 +++++++++++++++++++
 .../test/API/lang/cpp/enum_promotion/main.cpp | 22 +++++++++++
 3 files changed, 62 insertions(+)
 create mode 100644 lldb/test/API/lang/cpp/enum_promotion/Makefile
 create mode 100644 lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
 create mode 100644 lldb/test/API/lang/cpp/enum_promotion/main.cpp

diff --git a/lldb/test/API/lang/cpp/enum_promotion/Makefile b/lldb/test/API/lang/cpp/enum_promotion/Makefile
new file mode 100644
index 000000000000000..99998b20bcb0502
--- /dev/null
+++ b/lldb/test/API/lang/cpp/enum_promotion/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
diff --git a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
new file mode 100644
index 000000000000000..a4eed53c8d80f2e
--- /dev/null
+++ b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
@@ -0,0 +1,37 @@
+"""
+Test LLDB type promotion of unscoped enums.
+"""
+
+import lldb
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestCPPEnumPromotion(TestBase):
+
+    @skipIf(debug_info=no_match(["dwarf", "dwo"]))
+    def test(self):
+        self.build()
+        lldbutil.run_to_source_breakpoint(
+            self, "// break here", lldb.SBFileSpec("main.cpp")
+        )
+        UChar_promoted = self.frame().FindVariable("UChar_promoted")
+        UShort_promoted = self.frame().FindVariable("UShort_promoted")
+        UInt_promoted = self.frame().FindVariable("UInt_promoted")
+        SLong_promoted = self.frame().FindVariable("SLong_promoted")
+        ULong_promoted = self.frame().FindVariable("ULong_promoted")
+        NChar_promoted = self.frame().FindVariable("NChar_promoted")
+        NShort_promoted = self.frame().FindVariable("NShort_promoted")
+        NInt_promoted = self.frame().FindVariable("NInt_promoted")
+        NLong_promoted = self.frame().FindVariable("NLong_promoted")
+
+        # Check that LLDB's promoted type is the same as the compiler's
+        self.expect_expr("+EnumUChar::UChar", result_type=UChar_promoted.type.name)
+        self.expect_expr("+EnumUShort::UShort", result_type=UShort_promoted.type.name)
+        self.expect_expr("+EnumUInt::UInt", result_type=UInt_promoted.type.name)
+        self.expect_expr("+EnumSLong::SLong", result_type=SLong_promoted.type.name)
+        self.expect_expr("+EnumULong::ULong", result_type=ULong_promoted.type.name)
+        self.expect_expr("+EnumNChar::NChar", result_type=NChar_promoted.type.name)
+        self.expect_expr("+EnumNShort::NShort", result_type=NShort_promoted.type.name)
+        self.expect_expr("+EnumNInt::NInt", result_type=NInt_promoted.type.name)
+        self.expect_expr("+EnumNLong::NLong", result_type=NLong_promoted.type.name)
diff --git a/lldb/test/API/lang/cpp/enum_promotion/main.cpp b/lldb/test/API/lang/cpp/enum_promotion/main.cpp
new file mode 100644
index 000000000000000..fafb96f6c7b075a
--- /dev/null
+++ b/lldb/test/API/lang/cpp/enum_promotion/main.cpp
@@ -0,0 +1,22 @@
+enum EnumUChar { UChar = 1 };
+enum EnumUShort { UShort = 0x101 };
+enum EnumUInt { UInt = 0x10001 };
+enum EnumSLong { SLong = 0x100000001 };
+enum EnumULong { ULong = 0xFFFFFFFFFFFFFFF0 };
+enum EnumNChar { NChar = -1 };
+enum EnumNShort { NShort= -0x101 };
+enum EnumNInt { NInt = -0x10001 };
+enum EnumNLong { NLong = -0x100000001 };
+
+int main() {
+  auto UChar_promoted = +EnumUChar::UChar;
+  auto UShort_promoted = +EnumUShort::UShort;
+  auto UInt_promoted = +EnumUInt::UInt;
+  auto SLong_promoted = +EnumSLong::SLong;
+  auto ULong_promoted = +EnumULong::ULong;
+  auto NChar_promoted = +EnumNChar::NChar;
+  auto NShort_promoted = +EnumNShort::NShort;
+  auto NInt_promoted = +EnumNInt::NInt;
+  auto NLong_promoted = +EnumNLong::NLong;
+  return 0; // break here
+}

>From 8bec472e48834cf8dcd38bd8526c7446a0f89363 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Tue, 5 Nov 2024 20:10:58 +0500
Subject: [PATCH 04/13] Fix formatting

---
 lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py | 2 +-
 lldb/test/API/lang/cpp/enum_promotion/main.cpp                | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
index a4eed53c8d80f2e..3cf110441a0ae7c 100644
--- a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
+++ b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
@@ -7,8 +7,8 @@
 from lldbsuite.test.lldbtest import *
 from lldbsuite.test import lldbutil
 
-class TestCPPEnumPromotion(TestBase):
 
+class TestCPPEnumPromotion(TestBase):
     @skipIf(debug_info=no_match(["dwarf", "dwo"]))
     def test(self):
         self.build()
diff --git a/lldb/test/API/lang/cpp/enum_promotion/main.cpp b/lldb/test/API/lang/cpp/enum_promotion/main.cpp
index fafb96f6c7b075a..bcdb0adff5d401b 100644
--- a/lldb/test/API/lang/cpp/enum_promotion/main.cpp
+++ b/lldb/test/API/lang/cpp/enum_promotion/main.cpp
@@ -4,7 +4,7 @@ enum EnumUInt { UInt = 0x10001 };
 enum EnumSLong { SLong = 0x100000001 };
 enum EnumULong { ULong = 0xFFFFFFFFFFFFFFF0 };
 enum EnumNChar { NChar = -1 };
-enum EnumNShort { NShort= -0x101 };
+enum EnumNShort { NShort = -0x101 };
 enum EnumNInt { NInt = -0x10001 };
 enum EnumNLong { NLong = -0x100000001 };
 

>From 77c262dcb59913ebd591e860d7db59603e732811 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Fri, 20 Dec 2024 23:52:16 +0500
Subject: [PATCH 05/13] Move enum type and width computations to a separate
 function

---
 clang/include/clang/Sema/Sema.h               |  7 ++
 clang/lib/Sema/SemaDecl.cpp                   | 81 +++++++++++++++++++
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 65 ++-------------
 3 files changed, 96 insertions(+), 57 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 4d6e02fe2956e0c..39c97f0bc8fea60 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3994,6 +3994,13 @@ class Sema final : public SemaBase {
                           SourceLocation IdLoc, IdentifierInfo *Id,
                           const ParsedAttributesView &Attrs,
                           SourceLocation EqualLoc, Expr *Val);
+
+  bool ComputeBestEnumProperties(ASTContext &Context, EnumDecl *Enum,
+                                 bool isCpp, bool isPacked,
+                                 unsigned NumNegativeBits,
+                                 unsigned NumPositiveBits, unsigned &BestWidth,
+                                 QualType &BestType,
+                                 QualType &BestPromotionType);
   void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
                      Decl *EnumDecl, ArrayRef<Decl *> Elements, Scope *S,
                      const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c3ff247a6316d30..6bb576eb735a197 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20036,6 +20036,87 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
   return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val));
 }
 
+bool Sema::ComputeBestEnumProperties(ASTContext &Context, EnumDecl *Enum,
+                                     bool is_cpp, bool isPacked,
+                                     unsigned NumNegativeBits,
+                                     unsigned NumPositiveBits,
+                                     unsigned &BestWidth, QualType &BestType,
+                                     QualType &BestPromotionType) {
+  unsigned IntWidth = Context.getTargetInfo().getIntWidth();
+  unsigned CharWidth = Context.getTargetInfo().getCharWidth();
+  unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
+  bool enum_too_large = false;
+  if (NumNegativeBits) {
+    // If there is a negative value, figure out the smallest integer type (of
+    // int/long/longlong) that fits.
+    // If it's packed, check also if it fits a char or a short.
+    if (isPacked && NumNegativeBits <= CharWidth &&
+        NumPositiveBits < CharWidth) {
+      BestType = Context.SignedCharTy;
+      BestWidth = CharWidth;
+    } else if (isPacked && NumNegativeBits <= ShortWidth &&
+               NumPositiveBits < ShortWidth) {
+      BestType = Context.ShortTy;
+      BestWidth = ShortWidth;
+    } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
+      BestType = Context.IntTy;
+      BestWidth = IntWidth;
+    } else {
+      BestWidth = Context.getTargetInfo().getLongWidth();
+
+      if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) {
+        BestType = Context.LongTy;
+      } else {
+        BestWidth = Context.getTargetInfo().getLongLongWidth();
+
+        if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
+          enum_too_large = true;
+        BestType = Context.LongLongTy;
+      }
+    }
+    BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType);
+  } else {
+    // If there is no negative value, figure out the smallest type that fits
+    // all of the enumerator values.
+    // If it's packed, check also if it fits a char or a short.
+    if (isPacked && NumPositiveBits <= CharWidth) {
+      BestType = Context.UnsignedCharTy;
+      BestPromotionType = Context.IntTy;
+      BestWidth = CharWidth;
+    } else if (isPacked && NumPositiveBits <= ShortWidth) {
+      BestType = Context.UnsignedShortTy;
+      BestPromotionType = Context.IntTy;
+      BestWidth = ShortWidth;
+    } else if (NumPositiveBits <= IntWidth) {
+      BestType = Context.UnsignedIntTy;
+      BestWidth = IntWidth;
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedIntTy
+                              : Context.IntTy;
+    } else if (NumPositiveBits <=
+               (BestWidth = Context.getTargetInfo().getLongWidth())) {
+      BestType = Context.UnsignedLongTy;
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedLongTy
+                              : Context.LongTy;
+    } else {
+      BestWidth = Context.getTargetInfo().getLongLongWidth();
+      if (NumPositiveBits > BestWidth) {
+        // This can happen with bit-precise integer types, but those are not
+        // allowed as the type for an enumerator per C23 6.7.2.2p4 and p12.
+        // FIXME: GCC uses __int128_t and __uint128_t for cases that fit within
+        // a 128-bit integer, we should consider doing the same.
+        enum_too_large = true;
+      }
+      BestType = Context.UnsignedLongLongTy;
+      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
+                              ? Context.UnsignedLongLongTy
+                              : Context.LongLongTy;
+    }
+  }
+  return enum_too_large;
+}
+
 void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
                          Decl *EnumDeclX, ArrayRef<Decl *> Elements, Scope *S,
                          const ParsedAttributesView &Attrs) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 676cc7d7603655e..2bc899e5b9edec1 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2401,69 +2401,20 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   enum_decl->setNumPositiveBits(NumPositiveBits);
   enum_decl->setNumNegativeBits(NumNegativeBits);
 
-  // C++0x N3000 [conv.prom]p3:
-  //   An rvalue of an unscoped enumeration type whose underlying
-  //   type is not fixed can be converted to an rvalue of the first
-  //   of the following types that can represent all the values of
-  //   the enumeration: int, unsigned int, long int, unsigned long
-  //   int, long long int, or unsigned long long int.
-  // C99 6.4.4.3p2:
-  //   An identifier declared as an enumeration constant has type int.
-  // The C99 rule is modified by C23.
+  auto ts_ptr = clang_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
+  if (!ts_ptr)
+    return enumerators_added;
+
   clang::QualType BestPromotionType;
+  clang::QualType BestType;
   unsigned BestWidth;
 
   auto &Context = m_ast.getASTContext();
-  unsigned LongWidth = Context.getTargetInfo().getLongWidth();
-  unsigned IntWidth = Context.getTargetInfo().getIntWidth();
-  unsigned CharWidth = Context.getTargetInfo().getCharWidth();
-  unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
-
   bool is_cpp = Language::LanguageIsCPlusPlus(
       SymbolFileDWARF::GetLanguage(*parent_die.GetCU()));
-
-  if (NumNegativeBits) {
-    // If there is a negative value, figure out the smallest integer type (of
-    // int/long/longlong) that fits.
-    if (NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
-      BestWidth = CharWidth;
-    } else if (NumNegativeBits <= ShortWidth && NumPositiveBits < ShortWidth) {
-      BestWidth = ShortWidth;
-    } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
-      BestWidth = IntWidth;
-    } else if (NumNegativeBits <= LongWidth && NumPositiveBits < LongWidth) {
-      BestWidth = LongWidth;
-    } else {
-      BestWidth = Context.getTargetInfo().getLongLongWidth();
-    }
-    BestPromotionType =
-        BestWidth <= IntWidth ? Context.IntTy : enum_decl->getIntegerType();
-  } else {
-    // If there is no negative value, figure out the smallest type that fits
-    // all of the enumerator values.
-    if (NumPositiveBits <= CharWidth) {
-      BestPromotionType = Context.IntTy;
-      BestWidth = CharWidth;
-    } else if (NumPositiveBits <= ShortWidth) {
-      BestPromotionType = Context.IntTy;
-      BestWidth = ShortWidth;
-    } else if (NumPositiveBits <= IntWidth) {
-      BestWidth = IntWidth;
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedIntTy
-                              : Context.IntTy;
-    } else if (NumPositiveBits <= LongWidth) {
-      BestWidth = LongWidth;
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedLongTy
-                              : Context.LongTy;
-    } else {
-      BestWidth = Context.getTargetInfo().getLongLongWidth();
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedLongLongTy
-                              : Context.LongLongTy;
-    }
-  }
+  ts_ptr->getSema()->ComputeBestEnumProperties(
+      Context, enum_decl, is_cpp, false, NumNegativeBits, NumPositiveBits,
+      BestWidth, BestType, BestPromotionType);
   enum_decl->setPromotionType(BestPromotionType);
 
   return enumerators_added;

>From 4abfc5ab45b785580c88dfa9c2d5238dbf89d958 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 27 Jan 2025 20:29:52 +0500
Subject: [PATCH 06/13] Use computeBestEnumTypes() from ASTContext & cleanup
 code

---
 clang/include/clang/Sema/Sema.h               |  7 --
 clang/lib/Sema/SemaDecl.cpp                   | 81 -------------------
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 20 +----
 3 files changed, 2 insertions(+), 106 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 39c97f0bc8fea60..4d6e02fe2956e0c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3994,13 +3994,6 @@ class Sema final : public SemaBase {
                           SourceLocation IdLoc, IdentifierInfo *Id,
                           const ParsedAttributesView &Attrs,
                           SourceLocation EqualLoc, Expr *Val);
-
-  bool ComputeBestEnumProperties(ASTContext &Context, EnumDecl *Enum,
-                                 bool isCpp, bool isPacked,
-                                 unsigned NumNegativeBits,
-                                 unsigned NumPositiveBits, unsigned &BestWidth,
-                                 QualType &BestType,
-                                 QualType &BestPromotionType);
   void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
                      Decl *EnumDecl, ArrayRef<Decl *> Elements, Scope *S,
                      const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 6bb576eb735a197..c3ff247a6316d30 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20036,87 +20036,6 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
   return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val));
 }
 
-bool Sema::ComputeBestEnumProperties(ASTContext &Context, EnumDecl *Enum,
-                                     bool is_cpp, bool isPacked,
-                                     unsigned NumNegativeBits,
-                                     unsigned NumPositiveBits,
-                                     unsigned &BestWidth, QualType &BestType,
-                                     QualType &BestPromotionType) {
-  unsigned IntWidth = Context.getTargetInfo().getIntWidth();
-  unsigned CharWidth = Context.getTargetInfo().getCharWidth();
-  unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
-  bool enum_too_large = false;
-  if (NumNegativeBits) {
-    // If there is a negative value, figure out the smallest integer type (of
-    // int/long/longlong) that fits.
-    // If it's packed, check also if it fits a char or a short.
-    if (isPacked && NumNegativeBits <= CharWidth &&
-        NumPositiveBits < CharWidth) {
-      BestType = Context.SignedCharTy;
-      BestWidth = CharWidth;
-    } else if (isPacked && NumNegativeBits <= ShortWidth &&
-               NumPositiveBits < ShortWidth) {
-      BestType = Context.ShortTy;
-      BestWidth = ShortWidth;
-    } else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
-      BestType = Context.IntTy;
-      BestWidth = IntWidth;
-    } else {
-      BestWidth = Context.getTargetInfo().getLongWidth();
-
-      if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) {
-        BestType = Context.LongTy;
-      } else {
-        BestWidth = Context.getTargetInfo().getLongLongWidth();
-
-        if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
-          enum_too_large = true;
-        BestType = Context.LongLongTy;
-      }
-    }
-    BestPromotionType = (BestWidth <= IntWidth ? Context.IntTy : BestType);
-  } else {
-    // If there is no negative value, figure out the smallest type that fits
-    // all of the enumerator values.
-    // If it's packed, check also if it fits a char or a short.
-    if (isPacked && NumPositiveBits <= CharWidth) {
-      BestType = Context.UnsignedCharTy;
-      BestPromotionType = Context.IntTy;
-      BestWidth = CharWidth;
-    } else if (isPacked && NumPositiveBits <= ShortWidth) {
-      BestType = Context.UnsignedShortTy;
-      BestPromotionType = Context.IntTy;
-      BestWidth = ShortWidth;
-    } else if (NumPositiveBits <= IntWidth) {
-      BestType = Context.UnsignedIntTy;
-      BestWidth = IntWidth;
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedIntTy
-                              : Context.IntTy;
-    } else if (NumPositiveBits <=
-               (BestWidth = Context.getTargetInfo().getLongWidth())) {
-      BestType = Context.UnsignedLongTy;
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedLongTy
-                              : Context.LongTy;
-    } else {
-      BestWidth = Context.getTargetInfo().getLongLongWidth();
-      if (NumPositiveBits > BestWidth) {
-        // This can happen with bit-precise integer types, but those are not
-        // allowed as the type for an enumerator per C23 6.7.2.2p4 and p12.
-        // FIXME: GCC uses __int128_t and __uint128_t for cases that fit within
-        // a 128-bit integer, we should consider doing the same.
-        enum_too_large = true;
-      }
-      BestType = Context.UnsignedLongLongTy;
-      BestPromotionType = (NumPositiveBits == BestWidth || !is_cpp)
-                              ? Context.UnsignedLongLongTy
-                              : Context.LongLongTy;
-    }
-  }
-  return enum_too_large;
-}
-
 void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
                          Decl *EnumDeclX, ArrayRef<Decl *> Elements, Scope *S,
                          const ParsedAttributesView &Attrs) {
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 2bc899e5b9edec1..6da1f93a79a2c75 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2387,12 +2387,6 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     }
   }
 
-  /// The following code follows the same logic as in Sema::ActOnEnumBody
-  /// clang/lib/Sema/SemaDecl.cpp
-  // If we have an empty set of enumerators we still need one bit.
-  // From [dcl.enum]p8
-  // If the enumerator-list is empty, the values of the enumeration are as if
-  // the enumeration had a single enumerator with value 0
   if (!NumPositiveBits && !NumNegativeBits)
     NumPositiveBits = 1;
 
@@ -2401,20 +2395,10 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   enum_decl->setNumPositiveBits(NumPositiveBits);
   enum_decl->setNumNegativeBits(NumNegativeBits);
 
-  auto ts_ptr = clang_type.GetTypeSystem().dyn_cast_or_null<TypeSystemClang>();
-  if (!ts_ptr)
-    return enumerators_added;
-
   clang::QualType BestPromotionType;
   clang::QualType BestType;
-  unsigned BestWidth;
-
-  auto &Context = m_ast.getASTContext();
-  bool is_cpp = Language::LanguageIsCPlusPlus(
-      SymbolFileDWARF::GetLanguage(*parent_die.GetCU()));
-  ts_ptr->getSema()->ComputeBestEnumProperties(
-      Context, enum_decl, is_cpp, false, NumNegativeBits, NumPositiveBits,
-      BestWidth, BestType, BestPromotionType);
+  m_ast.getASTContext().computeBestEnumTypes(
+      false, NumNegativeBits, NumPositiveBits, BestType, BestPromotionType);
   enum_decl->setPromotionType(BestPromotionType);
 
   return enumerators_added;

>From e88c7e8f9198b2016d36b165c915ce05daed8629 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 27 Jan 2025 23:16:49 +0500
Subject: [PATCH 07/13] Add comments

---
 .../source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 6da1f93a79a2c75..01c70a30b2f2315 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2387,6 +2387,10 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     }
   }
 
+  // If we have an empty set of enumerators we still need one bit.
+  // From [dcl.enum]p8
+  // If the enumerator-list is empty, the values of the enumeration are as if
+  // the enumeration had a single enumerator with value 0
   if (!NumPositiveBits && !NumNegativeBits)
     NumPositiveBits = 1;
 
@@ -2398,7 +2402,7 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   clang::QualType BestPromotionType;
   clang::QualType BestType;
   m_ast.getASTContext().computeBestEnumTypes(
-      false, NumNegativeBits, NumPositiveBits, BestType, BestPromotionType);
+      /*IsPacked=*/false, NumNegativeBits, NumPositiveBits, BestType, BestPromotionType);
   enum_decl->setPromotionType(BestPromotionType);
 
   return enumerators_added;

>From 8625ab6b455f1c1ac62a0ef820bd21bb1a9e22f2 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Mon, 27 Jan 2025 23:49:02 +0500
Subject: [PATCH 08/13] Apply clang-format

---
 lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 01c70a30b2f2315..4b15d1747174113 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2402,7 +2402,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   clang::QualType BestPromotionType;
   clang::QualType BestType;
   m_ast.getASTContext().computeBestEnumTypes(
-      /*IsPacked=*/false, NumNegativeBits, NumPositiveBits, BestType, BestPromotionType);
+      /*IsPacked=*/false, NumNegativeBits, NumPositiveBits, BestType,
+      BestPromotionType);
   enum_decl->setPromotionType(BestPromotionType);
 
   return enumerators_added;

>From 1141fd0bf847b54d9b12c3a0aff093c02792e4de Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 30 Jan 2025 19:48:47 +0500
Subject: [PATCH 09/13] Move updating number of enum bits to a separate
 function

---
 clang/include/clang/AST/ASTContext.h               |  5 +++++
 clang/lib/AST/ASTContext.cpp                       | 14 ++++++++++++++
 clang/lib/Sema/SemaDecl.cpp                        | 12 ++----------
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp       | 11 ++---------
 4 files changed, 23 insertions(+), 19 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 65be782c1ba43e8..08ddf8db44cd480 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1726,6 +1726,11 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   QualType getEnumType(const EnumDecl *Decl) const;
 
+  /// Update the maximum amount of negative and positive bits
+  /// based on the provided enumerator value.
+  void updateNumOfEnumBits(llvm::APSInt *InitVal, unsigned &NumNegativeBits,
+                           unsigned &NumPositiveBits);
+
   /// Compute BestType and BestPromotionType for an enum based on the highest
   /// number of negative and positive bits of its elements.
   /// Returns true if enum width is too large.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cd1bcb3b9a063d8..f0e35d3cd589aa7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5240,6 +5240,20 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
   return QualType(newType, 0);
 }
 
+void ASTContext::updateNumOfEnumBits(llvm::APSInt *InitVal,
+                                     unsigned &NumNegativeBits,
+                                     unsigned &NumPositiveBits) {
+  if (InitVal->isUnsigned() || InitVal->isNonNegative()) {
+    // If the enumerator is zero that should still be counted as a positive
+    // bit since we need a bit to store the value zero.
+    unsigned ActiveBits = InitVal->getActiveBits();
+    NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+  } else {
+    NumNegativeBits =
+        std::max(NumNegativeBits, (unsigned)InitVal->getSignificantBits());
+  }
+}
+
 bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
                                       unsigned NumPositiveBits,
                                       QualType &BestType,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c3ff247a6316d30..e6e9a747e3ccaf2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20070,17 +20070,9 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
     if (!ECD) continue;  // Already issued a diagnostic.
 
     llvm::APSInt InitVal = ECD->getInitVal();
-
     // Keep track of the size of positive and negative values.
-    if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
-      // If the enumerator is zero that should still be counted as a positive
-      // bit since we need a bit to store the value zero.
-      unsigned ActiveBits = InitVal.getActiveBits();
-      NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
-    } else {
-      NumNegativeBits =
-          std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
-    }
+    Context.updateNumOfEnumBits(&InitVal, NumNegativeBits, NumPositiveBits);
+
     MembersRepresentableByInt &=
         isRepresentableIntegerValue(Context, InitVal, Context.IntTy);
   }
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 4b15d1747174113..09e341e9701503a 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2375,15 +2375,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 
       llvm::APSInt InitVal = ECD->getInitVal();
       // Keep track of the size of positive and negative values.
-      if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
-        // If the enumerator is zero that should still be counted as a positive
-        // bit since we need a bit to store the value zero.
-        unsigned ActiveBits = InitVal.getActiveBits();
-        NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
-      } else {
-        NumNegativeBits =
-            std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
-      }
+      m_ast.getASTContext().updateNumOfEnumBits(&InitVal, NumNegativeBits,
+                                                NumPositiveBits);
     }
   }
 

>From 56e8554e1a9b7b6817eca775f244c82087ea9659 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Thu, 30 Jan 2025 20:00:23 +0500
Subject: [PATCH 10/13] Add dSYM to the test

---
 lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
index 3cf110441a0ae7c..fdf33627e40a15e 100644
--- a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
+++ b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
@@ -9,7 +9,7 @@
 
 
 class TestCPPEnumPromotion(TestBase):
-    @skipIf(debug_info=no_match(["dwarf", "dwo"]))
+    @skipIf(debug_info=no_match(["dwarf", "dwo", "dsym"]))
     def test(self):
         self.build()
         lldbutil.run_to_source_breakpoint(

>From b581ad411d6e178300732410dd8850cd34543ac3 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Sat, 1 Feb 2025 00:40:43 +0500
Subject: [PATCH 11/13] Move computing NumNegativeBits and NumPositiveBits to a
 separate function

---
 clang/include/clang/AST/ASTContext.h          | 30 ++++++++++++++++---
 clang/lib/AST/ASTContext.cpp                  | 14 ---------
 clang/lib/Sema/SemaDecl.cpp                   | 13 +++-----
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  | 17 +++--------
 4 files changed, 34 insertions(+), 40 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index 08ddf8db44cd480..f84d11ef153d9de 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1726,11 +1726,33 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   QualType getEnumType(const EnumDecl *Decl) const;
 
-  /// Update the maximum amount of negative and positive bits
-  /// based on the provided enumerator value.
-  void updateNumOfEnumBits(llvm::APSInt *InitVal, unsigned &NumNegativeBits,
-                           unsigned &NumPositiveBits);
+  /// Compute the maximum number of negative and positive bits
+  /// of enum elements.
+  template <typename RangeT>
+  void computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits,
+                       unsigned &NumPositiveBits) {
+    for (auto ECD : EnumConstants) {
+      llvm::APSInt InitVal = ECD->getInitVal();
+      if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
+        // If the enumerator is zero that should still be counted as a positive
+        // bit since we need a bit to store the value zero.
+        unsigned ActiveBits = InitVal.getActiveBits();
+        NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+      } else {
+        NumNegativeBits =
+            std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
+      }
+    }
 
+    // If we have an empty set of enumerators we still need one bit.
+    // From [dcl.enum]p8
+    // If the enumerator-list is empty, the values of the enumeration are as if
+    // the enumeration had a single enumerator with value 0
+    if (!NumPositiveBits && !NumNegativeBits)
+      NumPositiveBits = 1;
+
+    return;
+  }
   /// Compute BestType and BestPromotionType for an enum based on the highest
   /// number of negative and positive bits of its elements.
   /// Returns true if enum width is too large.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index f0e35d3cd589aa7..cd1bcb3b9a063d8 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5240,20 +5240,6 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
   return QualType(newType, 0);
 }
 
-void ASTContext::updateNumOfEnumBits(llvm::APSInt *InitVal,
-                                     unsigned &NumNegativeBits,
-                                     unsigned &NumPositiveBits) {
-  if (InitVal->isUnsigned() || InitVal->isNonNegative()) {
-    // If the enumerator is zero that should still be counted as a positive
-    // bit since we need a bit to store the value zero.
-    unsigned ActiveBits = InitVal->getActiveBits();
-    NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
-  } else {
-    NumNegativeBits =
-        std::max(NumNegativeBits, (unsigned)InitVal->getSignificantBits());
-  }
-}
-
 bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
                                       unsigned NumPositiveBits,
                                       QualType &BestType,
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index e6e9a747e3ccaf2..f6e6cbce86e8411 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20064,25 +20064,20 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
   unsigned NumPositiveBits = 0;
   bool MembersRepresentableByInt = true;
 
+  llvm::SmallVector<EnumConstantDecl *> EnumConstants;
   for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
     EnumConstantDecl *ECD =
       cast_or_null<EnumConstantDecl>(Elements[i]);
     if (!ECD) continue;  // Already issued a diagnostic.
 
-    llvm::APSInt InitVal = ECD->getInitVal();
-    // Keep track of the size of positive and negative values.
-    Context.updateNumOfEnumBits(&InitVal, NumNegativeBits, NumPositiveBits);
+    EnumConstants.emplace_back(ECD);
 
+    llvm::APSInt InitVal = ECD->getInitVal();
     MembersRepresentableByInt &=
         isRepresentableIntegerValue(Context, InitVal, Context.IntTy);
   }
 
-  // If we have an empty set of enumerators we still need one bit.
-  // From [dcl.enum]p8
-  // If the enumerator-list is empty, the values of the enumeration are as if
-  // the enumeration had a single enumerator with value 0
-  if (!NumPositiveBits && !NumNegativeBits)
-    NumPositiveBits = 1;
+  Context.computeEnumBits(EnumConstants, NumNegativeBits, NumPositiveBits);
 
   // Figure out the type that should be used for this enum.
   QualType BestType;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 09e341e9701503a..915bef12a003b19 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -44,6 +44,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Type.h"
 #include "clang/Basic/Specifiers.h"
+#include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/DebugInfo/DWARF/DWARFAddressRange.h"
 #include "llvm/DebugInfo/DWARF/DWARFTypePrinter.h"
@@ -2369,26 +2370,16 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     }
 
     if (name && name[0] && got_value) {
-      auto ECD = m_ast.AddEnumerationValueToEnumerationType(
+      m_ast.AddEnumerationValueToEnumerationType(
           clang_type, decl, name, enum_value, enumerator_byte_size * 8);
       ++enumerators_added;
-
-      llvm::APSInt InitVal = ECD->getInitVal();
-      // Keep track of the size of positive and negative values.
-      m_ast.getASTContext().updateNumOfEnumBits(&InitVal, NumNegativeBits,
-                                                NumPositiveBits);
     }
   }
 
-  // If we have an empty set of enumerators we still need one bit.
-  // From [dcl.enum]p8
-  // If the enumerator-list is empty, the values of the enumeration are as if
-  // the enumeration had a single enumerator with value 0
-  if (!NumPositiveBits && !NumNegativeBits)
-    NumPositiveBits = 1;
-
   clang::EnumDecl *enum_decl =
       ClangUtil::GetQualType(clang_type)->getAs<clang::EnumType>()->getDecl();
+  m_ast.getASTContext().computeEnumBits(enum_decl->enumerators(),
+                                        NumNegativeBits, NumPositiveBits);
   enum_decl->setNumPositiveBits(NumPositiveBits);
   enum_decl->setNumNegativeBits(NumNegativeBits);
 

>From 6ea20e5ac930006c365b36d778d917f623e15337 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Sat, 1 Feb 2025 00:41:42 +0500
Subject: [PATCH 12/13] Remove test skipping

---
 lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
index fdf33627e40a15e..2a73dc5357fe785 100644
--- a/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
+++ b/lldb/test/API/lang/cpp/enum_promotion/TestCPPEnumPromotion.py
@@ -9,7 +9,6 @@
 
 
 class TestCPPEnumPromotion(TestBase):
-    @skipIf(debug_info=no_match(["dwarf", "dwo", "dsym"]))
     def test(self):
         self.build()
         lldbutil.run_to_source_breakpoint(

>From a02074cdff814a7f320420f459faea362a5b3109 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin <ikuklin at accesssoftek.com>
Date: Sat, 8 Feb 2025 20:54:33 +0500
Subject: [PATCH 13/13] Change computeEnumBits first argument to ArrayRef to
 avoid templating

---
 clang/include/clang/AST/ASTContext.h          | 32 +++----------
 clang/lib/AST/ASTContext.cpp                  | 48 +++++++++++++++++++
 clang/lib/Sema/SemaDecl.cpp                   | 41 ++--------------
 .../SymbolFile/DWARF/DWARFASTParserClang.cpp  |  9 ++--
 4 files changed, 65 insertions(+), 65 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h b/clang/include/clang/AST/ASTContext.h
index f84d11ef153d9de..4a67f554456b93f 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1726,33 +1726,15 @@ class ASTContext : public RefCountedBase<ASTContext> {
 
   QualType getEnumType(const EnumDecl *Decl) const;
 
-  /// Compute the maximum number of negative and positive bits
-  /// of enum elements.
-  template <typename RangeT>
-  void computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits,
-                       unsigned &NumPositiveBits) {
-    for (auto ECD : EnumConstants) {
-      llvm::APSInt InitVal = ECD->getInitVal();
-      if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
-        // If the enumerator is zero that should still be counted as a positive
-        // bit since we need a bit to store the value zero.
-        unsigned ActiveBits = InitVal.getActiveBits();
-        NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
-      } else {
-        NumNegativeBits =
-            std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
-      }
-    }
+  /// Determine whether the given integral value is representable within
+  /// the given type T.
+  bool isRepresentableIntegerValue(llvm::APSInt &Value, QualType T);
 
-    // If we have an empty set of enumerators we still need one bit.
-    // From [dcl.enum]p8
-    // If the enumerator-list is empty, the values of the enumeration are as if
-    // the enumeration had a single enumerator with value 0
-    if (!NumPositiveBits && !NumNegativeBits)
-      NumPositiveBits = 1;
+  /// Compute NumNegativeBits and NumPositiveBits for an enum based on
+  /// the constant values of its enumerators.
+  bool computeEnumBits(ArrayRef<Decl *> EnumConstants,
+                       unsigned &NumNegativeBits, unsigned &NumPositiveBits);
 
-    return;
-  }
   /// Compute BestType and BestPromotionType for an enum based on the highest
   /// number of negative and positive bits of its elements.
   /// Returns true if enum width is too large.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index cd1bcb3b9a063d8..6763482d6294799 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5319,6 +5319,54 @@ bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
   return EnumTooLarge;
 }
 
+bool ASTContext::isRepresentableIntegerValue(llvm::APSInt &Value, QualType T) {
+  assert((T->isIntegralType(*this) || T->isEnumeralType()) &&
+         "Integral type required!");
+  unsigned BitWidth = getIntWidth(T);
+
+  if (Value.isUnsigned() || Value.isNonNegative()) {
+    if (T->isSignedIntegerOrEnumerationType())
+      --BitWidth;
+    return Value.getActiveBits() <= BitWidth;
+  }
+  return Value.getSignificantBits() <= BitWidth;
+}
+
+bool ASTContext::computeEnumBits(ArrayRef<Decl *> EnumConstants,
+                                 unsigned &NumNegativeBits,
+                                 unsigned &NumPositiveBits) {
+  NumNegativeBits = 0;
+  NumPositiveBits = 0;
+  bool MembersRepresentableByInt = true;
+  for (auto *Elem : EnumConstants) {
+    EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elem);
+    if (!ECD)
+      continue; // Already issued a diagnostic.
+
+    llvm::APSInt InitVal = ECD->getInitVal();
+    if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
+      // If the enumerator is zero that should still be counted as a positive
+      // bit since we need a bit to store the value zero.
+      unsigned ActiveBits = InitVal.getActiveBits();
+      NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
+    } else {
+      NumNegativeBits =
+          std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
+    }
+
+    MembersRepresentableByInt &= isRepresentableIntegerValue(InitVal, IntTy);
+  }
+
+  // If we have an empty set of enumerators we still need one bit.
+  // From [dcl.enum]p8
+  // If the enumerator-list is empty, the values of the enumeration are as if
+  // the enumeration had a single enumerator with value 0
+  if (!NumPositiveBits && !NumNegativeBits)
+    NumPositiveBits = 1;
+
+  return MembersRepresentableByInt;
+}
+
 QualType ASTContext::getUnresolvedUsingType(
     const UnresolvedUsingTypenameDecl *Decl) const {
   if (Decl->TypeForDecl)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index f6e6cbce86e8411..41bb3ffeca3a9b3 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19524,23 +19524,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
   ProcessAPINotes(Record);
 }
 
-/// Determine whether the given integral value is representable within
-/// the given type T.
-static bool isRepresentableIntegerValue(ASTContext &Context,
-                                        llvm::APSInt &Value,
-                                        QualType T) {
-  assert((T->isIntegralType(Context) || T->isEnumeralType()) &&
-         "Integral type required!");
-  unsigned BitWidth = Context.getIntWidth(T);
-
-  if (Value.isUnsigned() || Value.isNonNegative()) {
-    if (T->isSignedIntegerOrEnumerationType())
-      --BitWidth;
-    return Value.getActiveBits() <= BitWidth;
-  }
-  return Value.getSignificantBits() <= BitWidth;
-}
-
 // Given an integral type, return the next larger integral type
 // (or a NULL type of no such type exists).
 static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
@@ -19614,7 +19597,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
           // representable in the underlying type of the enumeration. In C++11,
           // we perform a non-narrowing conversion as part of converted constant
           // expression checking.
-          if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
+          if (!Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
             if (Context.getTargetInfo()
                     .getTriple()
                     .isWindowsMSVCEnvironment()) {
@@ -19643,7 +19626,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
           //   representable as an int.
 
           // Complain if the value is not representable in an int.
-          if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) {
+          if (!Context.isRepresentableIntegerValue(EnumVal, Context.IntTy)) {
             Diag(IdLoc, getLangOpts().C23
                             ? diag::warn_c17_compat_enum_value_not_int
                             : diag::ext_c23_enum_value_not_int)
@@ -19735,7 +19718,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
                           : diag::ext_c23_enum_value_not_int)
               << 1 << toString(EnumVal, 10) << 1;
       } else if (!getLangOpts().CPlusPlus && !EltTy->isDependentType() &&
-                 !isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
+                 !Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
         // Enforce C99 6.7.2.2p2 even when we compute the next value.
         Diag(IdLoc, getLangOpts().C23 ? diag::warn_c17_compat_enum_value_not_int
                                       : diag::ext_c23_enum_value_not_int)
@@ -20062,22 +20045,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
   // reverse the list.
   unsigned NumNegativeBits = 0;
   unsigned NumPositiveBits = 0;
-  bool MembersRepresentableByInt = true;
-
-  llvm::SmallVector<EnumConstantDecl *> EnumConstants;
-  for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
-    EnumConstantDecl *ECD =
-      cast_or_null<EnumConstantDecl>(Elements[i]);
-    if (!ECD) continue;  // Already issued a diagnostic.
-
-    EnumConstants.emplace_back(ECD);
-
-    llvm::APSInt InitVal = ECD->getInitVal();
-    MembersRepresentableByInt &=
-        isRepresentableIntegerValue(Context, InitVal, Context.IntTy);
-  }
-
-  Context.computeEnumBits(EnumConstants, NumNegativeBits, NumPositiveBits);
+  bool MembersRepresentableByInt =
+      Context.computeEnumBits(Elements, NumNegativeBits, NumPositiveBits);
 
   // Figure out the type that should be used for this enum.
   QualType BestType;
diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
index 915bef12a003b19..ac425a1c87eda0c 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2319,7 +2319,7 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   size_t enumerators_added = 0;
   unsigned NumNegativeBits = 0;
   unsigned NumPositiveBits = 0;
-
+  llvm::SmallVector<clang::Decl *> EnumConstants;
   for (DWARFDIE die : parent_die.children()) {
     const dw_tag_t tag = die.Tag();
     if (tag != DW_TAG_enumerator)
@@ -2370,16 +2370,17 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
     }
 
     if (name && name[0] && got_value) {
-      m_ast.AddEnumerationValueToEnumerationType(
+      auto ECD = m_ast.AddEnumerationValueToEnumerationType(
           clang_type, decl, name, enum_value, enumerator_byte_size * 8);
+      EnumConstants.emplace_back(static_cast<clang::Decl *>(ECD));
       ++enumerators_added;
     }
   }
 
   clang::EnumDecl *enum_decl =
       ClangUtil::GetQualType(clang_type)->getAs<clang::EnumType>()->getDecl();
-  m_ast.getASTContext().computeEnumBits(enum_decl->enumerators(),
-                                        NumNegativeBits, NumPositiveBits);
+  m_ast.getASTContext().computeEnumBits(EnumConstants, NumNegativeBits,
+                                        NumPositiveBits);
   enum_decl->setNumPositiveBits(NumPositiveBits);
   enum_decl->setNumNegativeBits(NumNegativeBits);
 



More information about the lldb-commits mailing list