aboutsummaryrefslogtreecommitdiff
path: root/clang/lib
diff options
context:
space:
mode:
authorMariya Podchishchaeva <mariya.podchishchaeva@intel.com>2024-09-13 11:11:34 +0200
committerGitHub <noreply@github.com>2024-09-13 11:11:34 +0200
commita0f88901a4e6a6618c3ec02108103d0415e28834 (patch)
tree4208e1f031094170be1d72b287deabf68621c129 /clang/lib
parent1b57cbcf25fcc55235f9331535aef05324b6ca54 (diff)
downloadllvm-a0f88901a4e6a6618c3ec02108103d0415e28834.zip
llvm-a0f88901a4e6a6618c3ec02108103d0415e28834.tar.gz
llvm-a0f88901a4e6a6618c3ec02108103d0415e28834.tar.bz2
[clang][C23] Support N3029 Improved Normal Enumerations (#103917)
Basically clang already implemented 90% of the feature as an extension. This commit disables warnings for C23 and aligns types of enumerators according to the recent wording.
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaDecl.cpp58
1 files changed, 35 insertions, 23 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 3c6a0df..8557c25 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -19479,11 +19479,13 @@ 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))
- Diag(IdLoc, diag::ext_enum_value_not_int)
- << toString(EnumVal, 10) << Val->getSourceRange()
- << (EnumVal.isUnsigned() || EnumVal.isNonNegative());
- else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
+ if (!isRepresentableIntegerValue(Context, EnumVal, Context.IntTy)) {
+ Diag(IdLoc, getLangOpts().C23
+ ? diag::warn_c17_compat_enum_value_not_int
+ : diag::ext_c23_enum_value_not_int)
+ << 0 << toString(EnumVal, 10) << Val->getSourceRange()
+ << (EnumVal.isUnsigned() || EnumVal.isNonNegative());
+ } else if (!Context.hasSameType(Val->getType(), Context.IntTy)) {
// Force the type of the expression to 'int'.
Val = ImpCastExprToType(Val, Context.IntTy, CK_IntegralCast).get();
}
@@ -19558,17 +19560,22 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// If we're not in C++, diagnose the overflow of enumerator values,
// which in C99 means that the enumerator value is not representable in
- // an int (C99 6.7.2.2p2). However, we support GCC's extension that
- // permits enumerator values that are representable in some larger
- // integral type.
- if (!getLangOpts().CPlusPlus && !T.isNull())
- Diag(IdLoc, diag::warn_enum_value_overflow);
- } else if (!getLangOpts().CPlusPlus &&
- !EltTy->isDependentType() &&
+ // an int (C99 6.7.2.2p2). However C23 permits enumerator values that
+ // are representable in some larger integral type and we allow it in
+ // older language modes as an extension.
+ // Exclude fixed enumerators since they are diagnosed with an error for
+ // this case.
+ if (!getLangOpts().CPlusPlus && !T.isNull() && !Enum->isFixed())
+ Diag(IdLoc, getLangOpts().C23
+ ? diag::warn_c17_compat_enum_value_not_int
+ : diag::ext_c23_enum_value_not_int)
+ << 1 << toString(EnumVal, 10) << 1;
+ } else if (!getLangOpts().CPlusPlus && !EltTy->isDependentType() &&
!isRepresentableIntegerValue(Context, EnumVal, EltTy)) {
// Enforce C99 6.7.2.2p2 even when we compute the next value.
- Diag(IdLoc, diag::ext_enum_value_not_int)
- << toString(EnumVal, 10) << 1;
+ Diag(IdLoc, getLangOpts().C23 ? diag::warn_c17_compat_enum_value_not_int
+ : diag::ext_c23_enum_value_not_int)
+ << 1 << toString(EnumVal, 10) << 1;
}
}
}
@@ -19887,9 +19894,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
return;
}
- // TODO: If the result value doesn't fit in an int, it must be a long or long
- // long value. ISO C does not support this, but GCC does as an extension,
- // emit a warning.
unsigned IntWidth = Context.getTargetInfo().getIntWidth();
unsigned CharWidth = Context.getTargetInfo().getCharWidth();
unsigned ShortWidth = Context.getTargetInfo().getShortWidth();
@@ -19898,13 +19902,14 @@ 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.
- const llvm::APSInt &InitVal = ECD->getInitVal();
+ llvm::APSInt InitVal = ECD->getInitVal();
// Keep track of the size of positive and negative values.
if (InitVal.isUnsigned() || InitVal.isNonNegative()) {
@@ -19916,6 +19921,8 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
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.
@@ -19937,7 +19944,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
// 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 a gcc extension
+ // The C99 rule is modified by C23.
QualType BestPromotionType;
bool Packed = Enum->hasAttr<PackedAttr>();
@@ -20031,7 +20038,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
auto *ECD = cast_or_null<EnumConstantDecl>(D);
if (!ECD) continue; // Already issued a diagnostic.
- // Standard C says the enumerators have int type, but we allow, as an
+ // C99 says the enumerators have int type, but we allow, as an
// extension, the enumerators to be larger than int size. If each
// enumerator value fits in an int, type it as an int, otherwise type it the
// same as the enumerator decl itself. This means that in "enum { X = 1U }"
@@ -20045,9 +20052,14 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
QualType NewTy;
unsigned NewWidth;
bool NewSign;
- if (!getLangOpts().CPlusPlus &&
- !Enum->isFixed() &&
- isRepresentableIntegerValue(Context, InitVal, Context.IntTy)) {
+ if (!getLangOpts().CPlusPlus && !Enum->isFixed() &&
+ MembersRepresentableByInt) {
+ // C23 6.7.3.3.3p15:
+ // The enumeration member type for an enumerated type without fixed
+ // underlying type upon completion is:
+ // - int if all the values of the enumeration are representable as an
+ // int; or,
+ // - the enumerated type
NewTy = Context.IntTy;
NewWidth = IntWidth;
NewSign = true;