[clang] [clang][Sema] Cleanup and optimize DiagnoseAssignmentEnum (PR #141471)
Shafik Yaghmour via cfe-commits
cfe-commits at lists.llvm.org
Wed May 28 20:56:20 PDT 2025
Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm.org/llvm/llvm-project/pull/141471 at github.com>
================
@@ -1741,57 +1741,65 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
void
Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
Expr *SrcExpr) {
+
+ const auto *ET = DstType->getAs<EnumType>();
+ if (!ET)
+ return;
+
+ if (!SrcType->isIntegerType() ||
+ Context.hasSameUnqualifiedType(SrcType, DstType))
+ return;
+
+ if (SrcExpr->isTypeDependent() || SrcExpr->isValueDependent())
+ return;
+
+ const EnumDecl *ED = ET->getDecl();
+ if (!ED->isClosed())
+ return;
+
if (Diags.isIgnored(diag::warn_not_in_enum_assignment, SrcExpr->getExprLoc()))
return;
- if (const EnumType *ET = DstType->getAs<EnumType>())
- if (!Context.hasSameUnqualifiedType(SrcType, DstType) &&
- SrcType->isIntegerType()) {
- if (!SrcExpr->isTypeDependent() && !SrcExpr->isValueDependent() &&
- SrcExpr->isIntegerConstantExpr(Context)) {
- // Get the bitwidth of the enum value before promotions.
- unsigned DstWidth = Context.getIntWidth(DstType);
- bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
+ std::optional<llvm::APSInt> RHSVal = SrcExpr->getIntegerConstantExpr(Context);
+ if (!RHSVal)
+ return;
- llvm::APSInt RhsVal = SrcExpr->EvaluateKnownConstInt(Context);
- AdjustAPSInt(RhsVal, DstWidth, DstIsSigned);
- const EnumDecl *ED = ET->getDecl();
+ // Get the bitwidth of the enum value before promotions.
+ unsigned DstWidth = Context.getIntWidth(DstType);
+ bool DstIsSigned = DstType->isSignedIntegerOrEnumerationType();
+ AdjustAPSInt(*RHSVal, DstWidth, DstIsSigned);
- if (!ED->isClosed())
- return;
+ if (ED->hasAttr<FlagEnumAttr>()) {
+ if (!IsValueInFlagEnum(ED, *RHSVal, /*AllowMask=*/true))
+ Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
+ << DstType.getUnqualifiedType();
+ return;
+ }
- if (ED->hasAttr<FlagEnumAttr>()) {
- if (!IsValueInFlagEnum(ED, RhsVal, true))
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
- << DstType.getUnqualifiedType();
- } else {
- typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
- EnumValsTy;
- EnumValsTy EnumVals;
-
- // Gather all enum values, set their type and sort them,
- // allowing easier comparison with rhs constant.
- for (auto *EDI : ED->enumerators()) {
- llvm::APSInt Val = EDI->getInitVal();
- AdjustAPSInt(Val, DstWidth, DstIsSigned);
- EnumVals.push_back(std::make_pair(Val, EDI));
- }
- if (EnumVals.empty())
- return;
- llvm::stable_sort(EnumVals, CmpEnumVals);
- EnumValsTy::iterator EIend = llvm::unique(EnumVals, EqEnumVals);
-
- // See which values aren't in the enum.
- EnumValsTy::const_iterator EI = EnumVals.begin();
- while (EI != EIend && EI->first < RhsVal)
- EI++;
- if (EI == EIend || EI->first != RhsVal) {
- Diag(SrcExpr->getExprLoc(), diag::warn_not_in_enum_assignment)
- << DstType.getUnqualifiedType();
- }
- }
- }
- }
+ typedef SmallVector<std::pair<llvm::APSInt, EnumConstantDecl *>, 64>
+ EnumValsTy;
+ EnumValsTy EnumVals;
+
+ // Gather all enum values, set their type and sort them,
+ // allowing easier comparison with rhs constant.
+ for (auto *EDI : ED->enumerators()) {
----------------
shafik wrote:
It would be interesting to test the case in which we have a enum and the enumerators values are out of order to verify the sorting actually works as expected e.g.
```cpp
enum E {
E1 = 100,
E2 = 50,
E3 = 75,
E4 = 9,
E5 = 99
};
```
I don't see a test that verifies that but I could be missing it.
https://github.com/llvm/llvm-project/pull/141471
More information about the cfe-commits
mailing list