Skip to content

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

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1733,6 +1733,47 @@ class ASTContext : public RefCountedBase<ASTContext> {
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 <typename RangeT>
bool computeEnumBits(RangeT EnumConstants, unsigned &NumNegativeBits,
unsigned &NumPositiveBits) {
NumNegativeBits = 0;
NumPositiveBits = 0;
bool MembersRepresentableByInt = true;
for (auto *Elem : EnumConstants) {
EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elem);
if (!ECD)
continue; // Already issued a diagnostic.

llvm::APSInt InitVal = ECD->getInitVal();
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
// If the enumerator is zero that should still be counted as a positive
// bit since we need a bit to store the value zero.
unsigned ActiveBits = InitVal.getActiveBits();
NumPositiveBits = std::max({NumPositiveBits, ActiveBits, 1u});
} else {
NumNegativeBits =
std::max(NumNegativeBits, (unsigned)InitVal.getSignificantBits());
}

MembersRepresentableByInt &= isRepresentableIntegerValue(InitVal, IntTy);
}

// If we have an empty set of enumerators we still need one bit.
// From [dcl.enum]p8
// If the enumerator-list is empty, the values of the enumeration are as if
// the enumeration had a single enumerator with value 0
if (!NumPositiveBits && !NumNegativeBits)
NumPositiveBits = 1;

return MembersRepresentableByInt;
}

QualType
getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
54 changes: 5 additions & 49 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -19723,7 +19706,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// representable in the underlying type of the enumeration. In C++11,
// we perform a non-narrowing conversion as part of converted constant
// expression checking.
if (!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
if (!Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
if (Context.getTargetInfo()
.getTriple()
.isWindowsMSVCEnvironment()) {
Expand Down Expand Up @@ -19752,7 +19735,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// representable as an int.

// Complain if the value is not representable in an int.
if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) {
if (!Context.isRepresentableIntegerValue(EnumVal, Context.IntTy)) {
Diag(IdLoc, getLangOpts().C23
? diag::warn_c17_compat_enum_value_not_int
: diag::ext_c23_enum_value_not_int)
Expand Down Expand Up @@ -19844,7 +19827,7 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
: diag::ext_c23_enum_value_not_int)
<< 1 << toString(EnumVal, 10) << 1;
} else if (!getLangOpts().CPlusPlus && !EltTy->isDependentType() &&
!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
!Context.isRepresentableIntegerValue(EnumVal, EltTy)) {
// Enforce C99 6.7.2.2p2 even when we compute the next value.
Diag(IdLoc, getLangOpts().C23 ? diag::warn_c17_compat_enum_value_not_int
: diag::ext_c23_enum_value_not_int)
Expand Down Expand Up @@ -20171,35 +20154,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// reverse the list.
unsigned NumNegativeBits = 0;
unsigned NumPositiveBits = 0;
bool MembersRepresentableByInt = true;

for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
EnumConstantDecl *ECD =
cast_or_null<EnumConstantDecl>(Elements[i]);
if (!ECD) continue; // Already issued a diagnostic.

llvm::APSInt InitVal = ECD->getInitVal();

// Keep track of the size of positive and negative values.
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(Context, InitVal, Context.IntTy);
}

// If we have an empty set of enumerators we still need one bit.
// From [dcl.enum]p8
// If the enumerator-list is empty, the values of the enumeration are as if
// the enumeration had a single enumerator with value 0
if (!NumPositiveBits && !NumNegativeBits)
NumPositiveBits = 1;
bool MembersRepresentableByInt =
Context.computeEnumBits(Elements, NumNegativeBits, NumPositiveBits);

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