Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
5 changes: 5 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -3987,6 +3987,11 @@ class Sema final : public SemaBase {
SourceLocation IdLoc, IdentifierInfo *Id,
const ParsedAttributesView &Attrs,
SourceLocation EqualLoc, Expr *Val);

bool ComputeBestEnumProperties(ASTContext &Context, bool isPacked,
unsigned NumNegativeBits,
unsigned NumPositiveBits, QualType &BestType,
QualType &BestPromotionType);
void ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
Decl *EnumDecl, ArrayRef<Decl *> Elements, Scope *S,
const ParsedAttributesView &Attr);
Expand Down
162 changes: 91 additions & 71 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20008,6 +20008,90 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val));
}

bool Sema::ComputeBestEnumProperties(ASTContext &Context, bool isPacked,
unsigned NumNegativeBits,
unsigned NumPositiveBits,
QualType &BestType,
QualType &BestPromotionType) {
unsigned IntWidth = Context.getTargetInfo().getIntWidth();
unsigned CharWidth = Context.getTargetInfo().getCharWidth();
unsigned ShortWidth = Context.getTargetInfo().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 = 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)
EnumTooLarge = 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 || !Context.getLangOpts().CPlusPlus)
? Context.UnsignedIntTy
: Context.IntTy;
} else if (NumPositiveBits <=
(BestWidth = Context.getTargetInfo().getLongWidth())) {
BestType = Context.UnsignedLongTy;
BestPromotionType =
(NumPositiveBits == BestWidth || !Context.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.
EnumTooLarge = true;
}
BestType = Context.UnsignedLongLongTy;
BestPromotionType =
(NumPositiveBits == BestWidth || !Context.getLangOpts().CPlusPlus)
? Context.UnsignedLongLongTy
: Context.LongLongTy;
}
}
return EnumTooLarge;
}

void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
Decl *EnumDeclX, ArrayRef<Decl *> Elements, Scope *S,
const ParsedAttributesView &Attrs) {
Expand All @@ -20030,10 +20114,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 +20179,13 @@ 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 =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
bool EnumTooLarge =
const bool EnumTooLarge =

Copy link
Member

@Sirraide Sirraide Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Afaik we normally don’t do top-level const on local variables in Clang.

ComputeBestEnumProperties(Context, 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 +20217,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