Skip to content

Commit e3304f6

Browse files
kuilpdIcohedron
authored andcommitted
[clang][Sema] Move computing enum bits into a separate function (llvm#126096)
Move the code that computes `NumNegativeBits` and `NumPositiveBits` for an enum to a separate function in `ASTContext.h`. This function needs to be called from LLDB as well (llvm#115005)
1 parent 1dcb996 commit e3304f6

File tree

3 files changed

+59
-49
lines changed

3 files changed

+59
-49
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1733,6 +1733,47 @@ class ASTContext : public RefCountedBase<ASTContext> {
17331733
unsigned NumPositiveBits, QualType &BestType,
17341734
QualType &BestPromotionType);
17351735

1736+
/// Determine whether the given integral value is representable within
1737+
/// the given type T.
1738+
bool isRepresentableIntegerValue(llvm::APSInt &Value, QualType T);
1739+
1740+
/// Compute NumNegativeBits and NumPositiveBits for an enum based on
1741+
/// the constant values of its enumerators.
1742+
template <typename RangeT>
1743+
bool computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits,
1744+
unsigned &NumPositiveBits) {
1745+
NumNegativeBits = 0;
1746+
NumPositiveBits = 0;
1747+
bool MembersRepresentableByInt = true;
1748+
for (auto *Elem : EnumConstants) {
1749+
EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elem);
1750+
if (!ECD)
1751+
continue; // Already issued a diagnostic.
1752+
1753+
llvm::APSInt InitVal = ECD->getInitVal();
1754+
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
1755+
// If the enumerator is zero that should still be counted as a positive
1756+
// bit since we need a bit to store the value zero.
1757+
unsigned ActiveBits = InitVal.getActiveBits();
1758+
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
1759+
} else {
1760+
NumNegativeBits =
1761+
std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
1762+
}
1763+
1764+
MembersRepresentableByInt &= isRepresentableIntegerValue(InitVal, IntTy);
1765+
}
1766+
1767+
// If we have an empty set of enumerators we still need one bit.
1768+
// From [dcl.enum]p8
1769+
// If the enumerator-list is empty, the values of the enumeration are as if
1770+
// the enumeration had a single enumerator with value 0
1771+
if (!NumPositiveBits && !NumNegativeBits)
1772+
NumPositiveBits = 1;
1773+
1774+
return MembersRepresentableByInt;
1775+
}
1776+
17361777
QualType
17371778
getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;
17381779

clang/lib/AST/ASTContext.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5320,6 +5320,19 @@ bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
53205320
return EnumTooLarge;
53215321
}
53225322

5323+
bool ASTContext::isRepresentableIntegerValue(llvm::APSInt &Value, QualType T) {
5324+
assert((T->isIntegralType(*this) || T->isEnumeralType()) &&
5325+
"Integral type required!");
5326+
unsigned BitWidth = getIntWidth(T);
5327+
5328+
if (Value.isUnsigned() || Value.isNonNegative()) {
5329+
if (T->isSignedIntegerOrEnumerationType())
5330+
--BitWidth;
5331+
return Value.getActiveBits() <= BitWidth;
5332+
}
5333+
return Value.getSignificantBits() <= BitWidth;
5334+
}
5335+
53235336
QualType ASTContext::getUnresolvedUsingType(
53245337
const UnresolvedUsingTypenameDecl *Decl) const {
53255338
if (Decl->TypeForDecl)

clang/lib/Sema/SemaDecl.cpp

Lines changed: 5 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -19633,23 +19633,6 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
1963319633
ProcessAPINotes(Record);
1963419634
}
1963519635

19636-
/// Determine whether the given integral value is representable within
19637-
/// the given type T.
19638-
static bool isRepresentableIntegerValue(ASTContext &Context,
19639-
llvm::APSInt &Value,
19640-
QualType T) {
19641-
assert((T->isIntegralType(Context) || T->isEnumeralType()) &&
19642-
"Integral type required!");
19643-
unsigned BitWidth = Context.getIntWidth(T);
19644-
19645-
if (Value.isUnsigned() || Value.isNonNegative()) {
19646-
if (T->isSignedIntegerOrEnumerationType())
19647-
--BitWidth;
19648-
return Value.getActiveBits() <= BitWidth;
19649-
}
19650-
return Value.getSignificantBits() <= BitWidth;
19651-
}
19652-
1965319636
// Given an integral type, return the next larger integral type
1965419637
// (or a NULL type of no such type exists).
1965519638
static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
@@ -19723,7 +19706,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
1972319706
// representable in the underlying type of the enumeration. In C++11,
1972419707
// we perform a non-narrowing conversion as part of converted constant
1972519708
// expression checking.
19726-
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
19709+
if (!Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
1972719710
if (Context.getTargetInfo()
1972819711
.getTriple()
1972919712
.isWindowsMSVCEnvironment()) {
@@ -19752,7 +19735,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
1975219735
// representable as an int.
1975319736

1975419737
// Complain if the value is not representable in an int.
19755-
if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) {
19738+
if (!Context.isRepresentableIntegerValue(EnumVal, Context.IntTy)) {
1975619739
Diag(IdLoc, getLangOpts().C23
1975719740
? diag::warn_c17_compat_enum_value_not_int
1975819741
: diag::ext_c23_enum_value_not_int)
@@ -19844,7 +19827,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
1984419827
: diag::ext_c23_enum_value_not_int)
1984519828
<< 1 << toString(EnumVal, 10) << 1;
1984619829
} else if (!getLangOpts().CPlusPlus && !EltTy->isDependentType() &&
19847-
!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
19830+
!Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
1984819831
// Enforce C99 6.7.2.2p2 even when we compute the next value.
1984919832
Diag(IdLoc, getLangOpts().C23 ? diag::warn_c17_compat_enum_value_not_int
1985019833
: diag::ext_c23_enum_value_not_int)
@@ -20171,35 +20154,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
2017120154
// reverse the list.
2017220155
unsigned NumNegativeBits = 0;
2017320156
unsigned NumPositiveBits = 0;
20174-
bool MembersRepresentableByInt = true;
20175-
20176-
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
20177-
EnumConstantDecl *ECD =
20178-
cast_or_null<EnumConstantDecl>(Elements[i]);
20179-
if (!ECD) continue; // Already issued a diagnostic.
20180-
20181-
llvm::APSInt InitVal = ECD->getInitVal();
20182-
20183-
// Keep track of the size of positive and negative values.
20184-
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
20185-
// If the enumerator is zero that should still be counted as a positive
20186-
// bit since we need a bit to store the value zero.
20187-
unsigned ActiveBits = InitVal.getActiveBits();
20188-
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
20189-
} else {
20190-
NumNegativeBits =
20191-
std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
20192-
}
20193-
MembersRepresentableByInt &=
20194-
isRepresentableIntegerValue(Context, InitVal, Context.IntTy);
20195-
}
20196-
20197-
// If we have an empty set of enumerators we still need one bit.
20198-
// From [dcl.enum]p8
20199-
// If the enumerator-list is empty, the values of the enumeration are as if
20200-
// the enumeration had a single enumerator with value 0
20201-
if (!NumPositiveBits && !NumNegativeBits)
20202-
NumPositiveBits = 1;
20157+
bool MembersRepresentableByInt =
20158+
Context.computeEnumBits(Elements, NumNegativeBits, NumPositiveBits);
2020320159

2020420160
// Figure out the type that should be used for this enum.
2020520161
QualType BestType;

0 commit comments

Comments
 (0)