diff options
author | Mariya Podchishchaeva <mariya.podchishchaeva@intel.com> | 2024-09-13 11:11:34 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-09-13 11:11:34 +0200 |
commit | a0f88901a4e6a6618c3ec02108103d0415e28834 (patch) | |
tree | 4208e1f031094170be1d72b287deabf68621c129 /clang/lib | |
parent | 1b57cbcf25fcc55235f9331535aef05324b6ca54 (diff) | |
download | llvm-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.cpp | 58 |
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; |