-
Notifications
You must be signed in to change notification settings - Fork 14k
[clang][Sema] Cleanup and optimize DiagnoseAssignmentEnum #141471
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
Conversation
Reorder the precondition checks to move the costly onces last. Also, only evaluate the RHS once to get the integral value.
@llvm/pr-subscribers-clang Author: Timm Baeder (tbaederr) ChangesReorder the precondition checks to move the costly onces last. Also, only evaluate the RHS once to get the integral value. Full diff: https://github.com/llvm/llvm-project/pull/141471.diff 1 Files Affected:
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index ed070649dc1f9..08f77b2e246e9 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -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()) {
+ llvm::APSInt Val = EDI->getInitVal();
+ AdjustAPSInt(Val, DstWidth, DstIsSigned);
+ EnumVals.emplace_back(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();
+ }
}
StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc,
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks great imo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice change.
How are you coming up w/ the target for your improvements? Is this something other folks could try and try and find some inspiration?
|
||
// Gather all enum values, set their type and sort them, | ||
// allowing easier comparison with rhs constant. | ||
for (auto *EDI : ED->enumerators()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
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.
I ran the |
Reorder the precondition checks to move the costly onces last. Also, only evaluate the RHS once to get the integral value.
Reorder the precondition checks to move the costly onces last. Also, only evaluate the RHS once to get the integral value.