Skip to content

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

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 5 commits into from
Jan 17, 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
7 changes: 7 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1726,6 +1726,13 @@ class ASTContext : public RefCountedBase<ASTContext> {

QualType getEnumType(const EnumDecl *Decl) const;

/// Compute BestType and BestPromotionType for an enum based on the highest
/// number of negative and positive bits of its elements.
/// Returns true if enum width is too large.
bool computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
unsigned NumPositiveBits, QualType &BestType,
QualType &BestPromotionType);

QualType
getUnresolvedUsingType(const UnresolvedUsingTypenameDecl *Decl) const;

Expand Down
79 changes: 79 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5209,6 +5209,85 @@ QualType ASTContext::getEnumType(const EnumDecl *Decl) const {
return QualType(newType, 0);
}

bool ASTContext::computeBestEnumTypes(bool IsPacked, unsigned NumNegativeBits,
unsigned NumPositiveBits,
QualType &BestType,
QualType &BestPromotionType) {
unsigned IntWidth = Target->getIntWidth();
unsigned CharWidth = Target->getCharWidth();
unsigned ShortWidth = Target->getShortWidth();
bool EnumTooLarge = false;
unsigned BestWidth;
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 = SignedCharTy;
BestWidth = CharWidth;
} else if (IsPacked && NumNegativeBits <= ShortWidth &&
NumPositiveBits < ShortWidth) {
BestType = ShortTy;
BestWidth = ShortWidth;
} else if (NumNegativeBits <= IntWidth && NumPositiveBits < IntWidth) {
BestType = IntTy;
BestWidth = IntWidth;
} else {
BestWidth = Target->getLongWidth();

if (NumNegativeBits <= BestWidth && NumPositiveBits < BestWidth) {
BestType = LongTy;
} else {
BestWidth = Target->getLongLongWidth();

if (NumNegativeBits > BestWidth || NumPositiveBits >= BestWidth)
EnumTooLarge = true;
BestType = LongLongTy;
}
}
BestPromotionType = (BestWidth <= IntWidth ? 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 = UnsignedCharTy;
BestPromotionType = IntTy;
BestWidth = CharWidth;
} else if (IsPacked && NumPositiveBits <= ShortWidth) {
BestType = UnsignedShortTy;
BestPromotionType = IntTy;
BestWidth = ShortWidth;
} else if (NumPositiveBits <= IntWidth) {
BestType = UnsignedIntTy;
BestWidth = IntWidth;
BestPromotionType = (NumPositiveBits == BestWidth || !LangOpts.CPlusPlus)
? UnsignedIntTy
: IntTy;
} else if (NumPositiveBits <= (BestWidth = Target->getLongWidth())) {
BestType = UnsignedLongTy;
BestPromotionType = (NumPositiveBits == BestWidth || !LangOpts.CPlusPlus)
? UnsignedLongTy
: LongTy;
} else {
BestWidth = Target->getLongLongWidth();
if (NumPositiveBits > BestWidth) {
// This can happen with bit-precise integer types, but those are not
// allowed as the type for an enumerator per C23 6.7.2.2p4 and p12.
// FIXME: GCC uses __int128_t and __uint128_t for cases that fit within
// a 128-bit integer, we should consider doing the same.
EnumTooLarge = true;
}
BestType = UnsignedLongLongTy;
BestPromotionType = (NumPositiveBits == BestWidth || !LangOpts.CPlusPlus)
? UnsignedLongLongTy
: LongLongTy;
}
}
return EnumTooLarge;
}

QualType ASTContext::getUnresolvedUsingType(
const UnresolvedUsingTypenameDecl *Decl) const {
if (Decl->TypeForDecl)
Expand Down
77 changes: 6 additions & 71 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20030,10 +20030,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
return;
}

unsigned IntWidth = Context.getTargetInfo().getIntWidth();
unsigned CharWidth = Context.getTargetInfo().getCharWidth();
unsigned ShortWidth = Context.getTargetInfo().getShortWidth();

// Verify that all the values are okay, compute the size of the values, and
// reverse the list.
unsigned NumNegativeBits = 0;
Expand Down Expand Up @@ -20099,73 +20095,12 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
BestPromotionType = BestType;

BestWidth = Context.getIntWidth(BestType);
}
else 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 (Packed && NumNegativeBits <= CharWidth && NumPositiveBits < CharWidth) {
BestType = Context.SignedCharTy;
BestWidth = CharWidth;
} else if (Packed && 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)
Diag(Enum->getLocation(), diag::ext_enum_too_large);
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 (Packed && NumPositiveBits <= CharWidth) {
BestType = Context.UnsignedCharTy;
BestPromotionType = Context.IntTy;
BestWidth = CharWidth;
} else if (Packed && NumPositiveBits <= ShortWidth) {
BestType = Context.UnsignedShortTy;
BestPromotionType = Context.IntTy;
BestWidth = ShortWidth;
} else if (NumPositiveBits <= IntWidth) {
BestType = Context.UnsignedIntTy;
BestWidth = IntWidth;
BestPromotionType
= (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedIntTy : Context.IntTy;
} else if (NumPositiveBits <=
(BestWidth = Context.getTargetInfo().getLongWidth())) {
BestType = Context.UnsignedLongTy;
BestPromotionType
= (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedLongTy : Context.LongTy;
} else {
BestWidth = Context.getTargetInfo().getLongLongWidth();
if (NumPositiveBits > BestWidth) {
// This can happen with bit-precise integer types, but those are not
// allowed as the type for an enumerator per C23 6.7.2.2p4 and p12.
// FIXME: GCC uses __int128_t and __uint128_t for cases that fit within
// a 128-bit integer, we should consider doing the same.
Diag(Enum->getLocation(), diag::ext_enum_too_large);
}
BestType = Context.UnsignedLongLongTy;
BestPromotionType
= (NumPositiveBits == BestWidth || !getLangOpts().CPlusPlus)
? Context.UnsignedLongLongTy : Context.LongLongTy;
}
bool EnumTooLarge = Context.computeBestEnumTypes(
Packed, NumNegativeBits, NumPositiveBits, BestType, BestPromotionType);
BestWidth = Context.getIntWidth(BestType);
if (EnumTooLarge)
Diag(Enum->getLocation(), diag::ext_enum_too_large);
}

// Loop over all of the enumerator constants, changing their types to match
Expand Down Expand Up @@ -20197,7 +20132,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// int; or,
// - the enumerated type
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewWidth = Context.getTargetInfo().getIntWidth();
NewSign = true;
} else if (ECD->getType() == BestType) {
// Already the right type!
Expand Down
Loading