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

2024-11-05 Thread Ilia Kuklin via cfe-commits

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

The information about an enum's best promotion type is discarded after 
compilation and is not present in debug info. This patch repeats the same 
analysis of each enum value as in the front-end to determine the best promotion 
type during DWARF info parsing.

Fixes #86989

>From 5290832b802d98b9d293b6910c0837911ec490c4 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/3] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8c39ef3d5a9fa6..a78e6c92abb22b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3891,6 +3891,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) {
@@ -3902,7 +3903,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 a30d898a93cc4d..a21607c2020161 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2248,6 +2248,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();
@@ -2299,11 +2301,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()->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/longl

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

2024-11-05 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

My thought process for this patch: 
https://github.com/llvm/llvm-project/issues/86989#issuecomment-2438116468

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-11-05 Thread Ilia Kuklin via cfe-commits

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

>From 5290832b802d98b9d293b6910c0837911ec490c4 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/4] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8c39ef3d5a9fa6..a78e6c92abb22b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3891,6 +3891,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) {
@@ -3902,7 +3903,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 a30d898a93cc4d..a21607c2020161 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2248,6 +2248,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();
@@ -2299,11 +2301,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()->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 &

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

2024-11-05 Thread Ilia Kuklin via cfe-commits

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

>From 5290832b802d98b9d293b6910c0837911ec490c4 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/4] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8c39ef3d5a9fa6..a78e6c92abb22b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3891,6 +3891,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) {
@@ -3902,7 +3903,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 a30d898a93cc4d..a21607c2020161 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2248,6 +2248,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();
@@ -2299,11 +2301,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()->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 &

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

2024-11-05 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

> Not that this shouldn't be fixed, just weighing of the amount of complexity 
> added here versus the benefit.

I don't really know how useful it is in general to know the actual promotion 
type of the enum, I guess only for using enum values in expressions without 
explicit casting.

> Also, is this promotion-type something that can be encoded in DWARF? GCC 
> generates the same DWARF as Clang here. 

>From what I could tell there is nothing in the DWARF spec that allows to hold 
>a promotion type of an enum. We could just use some undocumented field, but 
>then it wouldn't work with GCC binaries.

> My question is: if the promotion type can be computed from the information in 
> dwarf (can it always?), and clang already has code to compute it (not from 
> DWARF, but from.. clang AST I guess), can we refactor that code somehow so 
> that it is usable from lldb as well?

It can be computed if all the enum values are present in DWARF. I thought about 
reusing the code from Sema as well, but it uses different interface to iterate 
through every value, and does other analysis along the way which is not needed 
during debugging anymore. Plus the patch allows to remove some of the erroneous 
analysis in 
[TypeSystemClang.cpp](https://github.com/llvm/llvm-project/pull/115005/files#diff-3a759ae917207e962f79e48fa280277099a587c11bc1f1385e64000c03d6b6a2)


https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-11-14 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

Ping

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-12-05 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

So, is this patch worth pursuing or is it too much code for a too specific use 
case?

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-24 Thread Ilia Kuklin via cfe-commits


@@ -20008,6 +20008,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,

kuilpd wrote:

Maybe better to put this function into `EnumDecl` itself? It has `ASTContext` 
within it filled on both Sema and LLDB side, and then `EnumDecl`  can fill it's 
own `BestType` and `BestPromotionType` fields using this function. 

https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum bits into a separate function (PR #126096)

2025-02-06 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

> > This is just moving stuff around so that seems fine. Though, I wonder, 
> > could we just pass e.g. an `ArrayRef` to `computeEnumBits()`? The 
> > LLDB pr you linked seems to have an `SmallVector`, so 
> > that should be possible (I think it does require a `reinterpret_cast` from 
> > a `const Decl**` to a `const EnumConstantDecl**`, but we already do that in 
> > other places in Clang iirc).
> 
> The reason I suggested the template initially was because in LLDB's case we 
> don't have the `EnumConstantDecl`s in a container. We only have an 
> `EnumDecl`. So the plan was to pass the `enumerators()` iterator into 
> `computeEnumBits`. But if you know of a good way to turn the range into a 
> container that we can pass as an `ArrayRef`, or some non-template way of 
> passing both an `iterator_range` and `ArrayRef` into `computeEnumBits`, 
> that'd be great!

Yeah, `enumerator()` returns 
`llvm::iterator_range>`, and couldn't 
find a good way to convert this to an `ArrayRef`.
I guess I could make a `SmallVector` and put the copy of 
pointers there at the point of their creation 
([here](https://github.com/llvm/llvm-project/blob/b581ad411d6e178300732410dd8850cd34543ac3/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp#L2373)),
 since the function return a `EnumConstantDecl`, then discard it.


https://github.com/llvm/llvm-project/pull/126096
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum bits into a separate function (PR #126096)

2025-02-06 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

The code needs to be called from LLDB as well (#115005), so this is an NFC 
patch to move it to `ASTContext.h`, plus this cleans up a bit the code in 
`Sema::ActOnEnumBody`. 
`isRepresentableIntegerValue` also had to be moved to `ASTContext.h`, but since 
it requires `ASTContext` as a first argument anyway, it seems like it's a 
better location for this function anyway.
The only question is that `computeEnumBits` has a raw template in order to 
function with different collections that Sema and LLDB use, so the function has 
to be defined in the header. Can this be a problem?

https://github.com/llvm/llvm-project/pull/126096
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum bits into a separate function (PR #126096)

2025-02-06 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd created 
https://github.com/llvm/llvm-project/pull/126096

Move the code that computes `NumNegativeBits` and `NumPositiveBits` for an enum 
to a separate function in `ASTContext.h`


>From bf58b01066421af318a7a69a3ac1632e69b29301 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Thu, 6 Feb 2025 00:53:09 +0500
Subject: [PATCH] [clang][Sema] Move computing enum bits into a separate
 function

---
 clang/include/clang/AST/ASTContext.h | 41 +
 clang/lib/AST/ASTContext.cpp | 13 +++
 clang/lib/Sema/SemaDecl.cpp  | 54 +++-
 3 files changed, 59 insertions(+), 49 deletions(-)

diff --git a/clang/include/clang/AST/ASTContext.h 
b/clang/include/clang/AST/ASTContext.h
index 65be782c1ba43e8..a96b9c0a17045af 100644
--- a/clang/include/clang/AST/ASTContext.h
+++ b/clang/include/clang/AST/ASTContext.h
@@ -1733,6 +1733,47 @@ class ASTContext : public RefCountedBase {
 unsigned NumPositiveBits, QualType &BestType,
 QualType &BestPromotionType);
 
+  /// Determine whether the given integral value is representable within
+  /// the given type T.
+  bool isRepresentableIntegerValue(llvm::APSInt &Value, QualType T);
+
+  /// Compute NumNegativeBits and NumPositiveBits for an enum based on
+  /// the constant values of its enumerators.
+  template 
+  bool computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits,
+   unsigned &NumPositiveBits) {
+NumNegativeBits = 0;
+NumPositiveBits = 0;
+bool MembersRepresentableByInt = true;
+for (auto *Elem : EnumConstants) {
+  EnumConstantDecl *ECD = cast_or_null(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
   getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;
 
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index de617860b70040b..3a2ccd3d2ddcbf4 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -5320,6 +5320,19 @@ 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;
+}
+
 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 74e0fcec2d911bc..6eedc77ed20a09e 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19633,23 +19633,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) {
@@ -19723,7 +19706,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl 
*Enum,
   // representab

[clang] [clang][Sema] Move computing enum bits into a separate function (PR #126096)

2025-02-06 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd edited 
https://github.com/llvm/llvm-project/pull/126096
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum bits into a separate function (PR #126096)

2025-02-11 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd closed 
https://github.com/llvm/llvm-project/pull/126096
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-30 Thread Ilia Kuklin via cfe-commits

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 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 01/10] [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 16403774e72b31..41cb47516f5803 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 e77188bfbd2e4a..bb9c35a235c1ff 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()->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 &

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

2025-01-30 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,38 @@ 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});

kuilpd wrote:

I don't think I can move the entire loop into a separate function, the way 
`DWARFASTParserClang` and `SemaDecl` iterate over enum values is completely 
different, so for now I just moved these few lines that determine the updated 
`NumPositiveBits` `NumNegativeBits`. 

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-31 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,36 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 }
 
 if (name && name[0] && got_value) {
-  m_ast.AddEnumerationValueToEnumerationType(
+  auto ECD = m_ast.AddEnumerationValueToEnumerationType(

kuilpd wrote:

Alright, will do, thank you!

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-31 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,36 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 }
 
 if (name && name[0] && got_value) {
-  m_ast.AddEnumerationValueToEnumerationType(
+  auto ECD = m_ast.AddEnumerationValueToEnumerationType(

kuilpd wrote:

It's used in 5 other places in `SemaDecl.cpp`, unfortunately, so it will have 
to be yet another `ASTContext` function.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-31 Thread Ilia Kuklin via cfe-commits

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 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 01/12] [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 16403774e72b31..41cb47516f5803 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 e77188bfbd2e4a..bb9c35a235c1ff 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()->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 &

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

2025-01-31 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,36 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 }
 
 if (name && name[0] && got_value) {
-  m_ast.AddEnumerationValueToEnumerationType(
+  auto ECD = m_ast.AddEnumerationValueToEnumerationType(

kuilpd wrote:

Well... I tried this, it works, but I encountered some problems:
1. `computeEnumBits` definition has to be in the header file, otherwise 
template instantiation doesn't work. I tried making the elements argument an 
`ArrayRef`, but it's also not working well with `enum_decl->enumerators()` 
returning `llvm::iterator_range>`
2. Iteration over elements in `SemaDecl.cpp` checks for the element is a 
`EnumConstantDecl`, otherwise it's skipped, so I had to create a separate 
collection in case something is removed, and then pass that one to 
`computeEnumBits`
3. `isRepresentableIntegerValue` is a static function in `SemaDecl.cpp`, I'd 
rather not move somewhere else as well, since it's not needed on LLDB side 
anyway

Mostly I'm just not sure if it's a problem or not that `ASTContext.h` contains 
a definition of a function.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-31 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,36 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 }
 
 if (name && name[0] && got_value) {
-  m_ast.AddEnumerationValueToEnumerationType(
+  auto ECD = m_ast.AddEnumerationValueToEnumerationType(

kuilpd wrote:

> > Iteration over elements in SemaDecl.cpp checks for the element is a 
> > EnumConstantDecl, otherwise it's skipped, so I had to create a separate 
> > collection in case something is removed, and then pass that one to 
> > computeEnumBits
> 
> Could you elaborate on this? LLDB only ever puts `EnumConstantDecl`s there 
> right?

This line: 
[SemaDecl.cpp:20070](https://github.com/llvm/llvm-project/blob/1141fd0bf847b54d9b12c3a0aff093c02792e4de/clang/lib/Sema/SemaDecl.cpp#L20070),
 if it discards something, I cannot pass the original `Elements` to 
`computeEnumBits`.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-31 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,36 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
 }
 
 if (name && name[0] && got_value) {
-  m_ast.AddEnumerationValueToEnumerationType(
+  auto ECD = m_ast.AddEnumerationValueToEnumerationType(

kuilpd wrote:

Yes, but I didn't want to move `isRepresentableIntegerValue` outside of 
`SemaDecl.cpp`, so I moved only the part that checks the bits. Seemed 
unnecessary to both move the static function and also use call it from LLDB 
where the result wouldn't be used anyway.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-12-20 Thread Ilia Kuklin via cfe-commits

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

>From 5290832b802d98b9d293b6910c0837911ec490c4 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/6] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index 8c39ef3d5a9fa6..a78e6c92abb22b 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3891,6 +3891,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) {
@@ -3902,7 +3903,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 a30d898a93cc4d..a21607c2020161 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2248,6 +2248,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();
@@ -2299,11 +2301,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()->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 &

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

2024-12-20 Thread Ilia Kuklin via cfe-commits


@@ -2299,11 +2301,103 @@ 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::EnumDecl *enum_decl =
+  ClangUtil::GetQualType(clang_type)->getAs()->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) {

kuilpd wrote:

If I understood you correctly, I created this separate function in clang's 
SemaDecl.cpp, and then called it from both LLDB and Sema itself. Seems to be 
working, but it needed a lot of arguments, since when called from LLDB Sema 
doesn't have any information stored at all, so ASTContext, EnumDecl and other 
arguments have to come from LLDB, and it also returns 3 values.
This looks clunky because of it, any suggestions how to make it better?

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2024-12-20 Thread Ilia Kuklin via cfe-commits


@@ -8544,7 +8524,8 @@ clang::EnumConstantDecl 
*TypeSystemClang::AddEnumerationValueToEnumerationType(
   bool is_signed = false;
   underlying_type.IsIntegerType(is_signed);
 
-  llvm::APSInt value(enum_value_bit_size, is_signed);
+  // APSInt constructor's sign argument is isUnsigned
+  llvm::APSInt value(enum_value_bit_size, !is_signed);

kuilpd wrote:

Made a PR #120794, once it's merged I will rebase this branch on main and run 
tests again.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-27 Thread Ilia Kuklin via cfe-commits

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 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/6] [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 16403774e72b31..41cb47516f5803 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 e77188bfbd2e4a..bb9c35a235c1ff 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()->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 && 

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

2025-01-27 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,38 @@ 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});

kuilpd wrote:

The condition checks that the value is just non negative unsigned, so I think 
the comment means that it could be zero, in which case the max function would 
prefer `1u` over it. 

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-27 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd edited 
https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-27 Thread Ilia Kuklin via cfe-commits

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 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/7] [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 16403774e72b31..41cb47516f5803 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 e77188bfbd2e4a..bb9c35a235c1ff 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()->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 && 

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

2025-01-27 Thread Ilia Kuklin via cfe-commits


@@ -2367,11 +2369,38 @@ 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());

kuilpd wrote:

This one is for when the value is just signed negative, can be anything, 
accumulates over all enum values.
This if/else is from 
[SemaDecl.cpp:L20084](https://github.com/llvm/llvm-project/blob/5d6d982df61d16b6d498e6d59dd91c059679d3d8/clang/lib/Sema/SemaDecl.cpp#L20084),
 but I don't think this few lines are worth putting into a separate function as 
well.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-27 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

@Michael137 
Reused the code I merged in #120965 to get the best promotion type.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-01-27 Thread Ilia Kuklin via cfe-commits

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 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 1/8] [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 16403774e72b31..41cb47516f5803 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 e77188bfbd2e4a..bb9c35a235c1ff 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()->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 && 

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

2025-01-27 Thread Ilia Kuklin via cfe-commits


@@ -3903,6 +3903,7 @@ class EnumDecl : public TagDecl {
   void setInstantiationOfMemberEnum(ASTContext &C, EnumDecl *ED,
 TemplateSpecializationKind TSK);
 
+public:

kuilpd wrote:

I left this in so that that I could simply do `enum_decl->setNumPositiveBits` 
in `DWARFASTParserClang.cpp` and then retrieve it via 
`enum_decl->getNumPositiveBits` in `TypeSystemClang.cpp`.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-14 Thread Ilia Kuklin via cfe-commits

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

>From ab8dcaef120233d0145508aaa4bf45eec22cadf1 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 23 Dec 2024 17:49:32 +0500
Subject: [PATCH 1/4] [clang][Sema] Move calculating enum width and type to a
 separate function

---
 clang/include/clang/Sema/Sema.h |   7 ++
 clang/lib/Sema/SemaDecl.cpp | 158 ++--
 2 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..51a1721fb74f01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3987,6 +3987,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 Elements, Scope *S,
  const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..79cbfe3116b26b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20008,6 +20008,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 ca

[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-14 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

Tried moving the code to `EnumDecl`, but it didn't work as well as I thought, 
so moved it to `ASTContext` after all. Don't really know where exactly to place 
it inside `ASTContext.h`, though.

https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-23 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

As of now LLDB doesn't calculate enum's best promotion type when reading it 
from DWARF info. This change would allow to reuse the code from Sema without 
copying it to LLDB, which I'm working on in #115005 
This function however has too many arguments right now, and also needs to 
return 3 results, so I'd be grateful for some advice how to make it look better.

https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-23 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd created 
https://github.com/llvm/llvm-project/pull/120965

Move the code that calculates BestWidth, BestType and BestPromotionType for an 
enum to a separate function which can be called from outside of Sema.


>From ab8dcaef120233d0145508aaa4bf45eec22cadf1 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 23 Dec 2024 17:49:32 +0500
Subject: [PATCH] [clang][Sema] Move calculating enum width and type to a
 separate function

---
 clang/include/clang/Sema/Sema.h |   7 ++
 clang/lib/Sema/SemaDecl.cpp | 158 ++--
 2 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..51a1721fb74f01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3987,6 +3987,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 Elements, Scope *S,
  const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..79cbfe3116b26b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20008,6 +20008,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
+  : Contex

[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-23 Thread Ilia Kuklin via cfe-commits

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

>From ab8dcaef120233d0145508aaa4bf45eec22cadf1 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 23 Dec 2024 17:49:32 +0500
Subject: [PATCH 1/2] [clang][Sema] Move calculating enum width and type to a
 separate function

---
 clang/include/clang/Sema/Sema.h |   7 ++
 clang/lib/Sema/SemaDecl.cpp | 158 ++--
 2 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..51a1721fb74f01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3987,6 +3987,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 Elements, Scope *S,
  const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..79cbfe3116b26b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20008,6 +20008,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 ca

[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-23 Thread Ilia Kuklin via cfe-commits

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

>From ab8dcaef120233d0145508aaa4bf45eec22cadf1 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 23 Dec 2024 17:49:32 +0500
Subject: [PATCH 1/2] [clang][Sema] Move calculating enum width and type to a
 separate function

---
 clang/include/clang/Sema/Sema.h |   7 ++
 clang/lib/Sema/SemaDecl.cpp | 158 ++--
 2 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..51a1721fb74f01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3987,6 +3987,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 Elements, Scope *S,
  const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..79cbfe3116b26b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20008,6 +20008,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 ca

[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2024-12-23 Thread Ilia Kuklin via cfe-commits


@@ -20008,6 +20008,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,

kuilpd wrote:

Removed `Enum`, `is_cpp` and `BestWidth`, but unfortunately when calling this 
function from LLDB, `Context` in Sema is empty, so it has to be passed as an 
argument.

https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-14 Thread Ilia Kuklin via cfe-commits

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

>From ab8dcaef120233d0145508aaa4bf45eec22cadf1 Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 23 Dec 2024 17:49:32 +0500
Subject: [PATCH 1/5] [clang][Sema] Move calculating enum width and type to a
 separate function

---
 clang/include/clang/Sema/Sema.h |   7 ++
 clang/lib/Sema/SemaDecl.cpp | 158 ++--
 2 files changed, 94 insertions(+), 71 deletions(-)

diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 5ee7ea48cc983c..51a1721fb74f01 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -3987,6 +3987,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 Elements, Scope *S,
  const ParsedAttributesView &Attr);
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 4001c4d263f1d2..79cbfe3116b26b 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -20008,6 +20008,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 ca

[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-16 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

Updated code, fixed nits.
@Fznamznon Does this look good to you too?


https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-10 Thread Ilia Kuklin via cfe-commits


@@ -20008,6 +20008,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,

kuilpd wrote:

> > EnumDecl can fill it's own BestType and BestPromotionType fields using this 
> > function.
> 
> I'm afraid it might result in EnumDecl taking more space and I don't think 
> we'd like that.

I'm sorry, I'm a bit confused here, what kind of space do you mean?
I suggest adding only one method to the class, nothing else.

https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing best enum types to a separate function (PR #120965)

2025-01-17 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd closed 
https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing best enum types to a separate function (PR #120965)

2025-01-17 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd edited 
https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang][Sema] Move computing enum width and type to a separate function (PR #120965)

2025-01-17 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd edited 
https://github.com/llvm/llvm-project/pull/120965
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-02-12 Thread Ilia Kuklin via cfe-commits

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

>From dd65babbf4c73a0b2fc2e4aa47a9a346bd5a9adf Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 01/14] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index f305cbbce4c60..177f7df5bfee8 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3910,6 +3910,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) {
@@ -3921,7 +3922,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 ec0004c70c6da..f8678909ce732 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2315,6 +2315,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,8 +2369,99 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   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()->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 && NumPosit

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

2025-02-13 Thread Ilia Kuklin via cfe-commits

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

>From dd65babbf4c73a0b2fc2e4aa47a9a346bd5a9adf Mon Sep 17 00:00:00 2001
From: Ilia Kuklin 
Date: Mon, 4 Nov 2024 14:33:45 +0500
Subject: [PATCH 01/15] [lldb] Analyze enum promotion type during parsing

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

diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h
index f305cbbce4c60..177f7df5bfee8 100644
--- a/clang/include/clang/AST/Decl.h
+++ b/clang/include/clang/AST/Decl.h
@@ -3910,6 +3910,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) {
@@ -3921,7 +3922,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 ec0004c70c6da..f8678909ce732 100644
--- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -2315,6 +2315,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,8 +2369,99 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
   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()->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 && NumPosit

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

2025-02-13 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

@Michael137 
Thank you for seeing this through!

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-02-08 Thread Ilia Kuklin via cfe-commits

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 
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()->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 <= IntWid

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

2025-02-08 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

@Michael137 
Changed the first argument of `computeEnumBits` to an `ArrayRef` to avoid the 
template and so it can be still seamlessly used from Sema.
On LLDB side, I had to create a `SmallVector` and put enum constants there at 
the point of their creation (`AddEnumerationValueToEnumerationType` returns a 
pointer anyway) so that it can be passed to `computeEnumBits` as is. It's only 
a vector of pointers, and it's discarded after, so if it's not a problem here, 
I'll make the same changes in the Sema PR.

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-02-13 Thread Ilia Kuklin via cfe-commits

https://github.com/kuilpd closed 
https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


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

2025-02-13 Thread Ilia Kuklin via cfe-commits

kuilpd wrote:

> But only for dSYMs. Looking at the `dSYM`, none of the enums are actually 
> preserved in the debug-info. You have to actually use the enum types in 
> source to get dsymutil to preserve them. I'll fix it

Ah, I see. Thank you for handling this!

https://github.com/llvm/llvm-project/pull/115005
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits