return New;
}
-// Emits a warning if every element in the enum is the same value and if
-// every element is initialized with a integer or boolean literal.
-static void CheckForUniqueEnumValues(Sema &S, Decl **Elements,
- unsigned NumElements, EnumDecl *Enum,
- QualType EnumType) {
- if (S.Diags.getDiagnosticLevel(diag::warn_identical_enum_values,
- Enum->getLocation()) ==
- DiagnosticsEngine::Ignored)
- return;
-
- if (NumElements < 2)
- return;
-
- if (!Enum->getIdentifier())
- return;
-
- llvm::APSInt FirstVal;
-
- for (unsigned i = 0; i != NumElements; ++i) {
- EnumConstantDecl *ECD = cast_or_null<EnumConstantDecl>(Elements[i]);
- if (!ECD)
- return;
-
- Expr *InitExpr = ECD->getInitExpr();
- if (!InitExpr)
- return;
- InitExpr = InitExpr->IgnoreImpCasts();
- if (!isa<IntegerLiteral>(InitExpr) && !isa<CXXBoolLiteralExpr>(InitExpr))
- return;
-
- if (i == 0) {
- FirstVal = ECD->getInitVal();
- continue;
- }
-
- if (!llvm::APSInt::isSameValue(FirstVal, ECD->getInitVal()))
- return;
- }
-
- S.Diag(Enum->getLocation(), diag::warn_identical_enum_values)
- << EnumType << FirstVal.toString(10)
- << Enum->getSourceRange();
-
- EnumConstantDecl *Last = cast<EnumConstantDecl>(Elements[NumElements - 1]),
- *Next = cast<EnumConstantDecl>(Elements[NumElements - 2]);
-
- S.Diag(Last->getLocation(), diag::note_identical_enum_values)
- << FixItHint::CreateReplacement(Last->getInitExpr()->getSourceRange(),
- Next->getName());
-}
-
-// Returns true when the enum initial expression does not trigger the
-// duplicate enum warning. A few common cases are exempted as follows:
-// Element2 = Element1
-// Element2 = Element1 + 1
-// Element2 = Element1 - 1
-// Where Element2 and Element1 are from the same enum.
-static bool ValidDuplicateEnum(EnumConstantDecl *ECD, EnumDecl *Enum) {
- Expr *InitExpr = ECD->getInitExpr();
- if (!InitExpr)
- return true;
- InitExpr = InitExpr->IgnoreImpCasts();
-
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(InitExpr)) {
- if (!BO->isAdditiveOp())
- return true;
- IntegerLiteral *IL = dyn_cast<IntegerLiteral>(BO->getRHS());
- if (!IL)
- return true;
- if (IL->getValue() != 1)
- return true;
-
- InitExpr = BO->getLHS();
- }
-
- // This checks if the elements are from the same enum.
- DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(InitExpr);
- if (!DRE)
- return true;
-
- EnumConstantDecl *EnumConstant = dyn_cast<EnumConstantDecl>(DRE->getDecl());
- if (!EnumConstant)
- return true;
-
- if (cast<EnumDecl>(TagDecl::castFromDeclContext(ECD->getDeclContext())) !=
- Enum)
- return true;
-
- return false;
-}
-
-struct DupKey {
- int64_t val;
- bool isTombstoneOrEmptyKey;
- DupKey(int64_t val, bool isTombstoneOrEmptyKey)
- : val(val), isTombstoneOrEmptyKey(isTombstoneOrEmptyKey) {}
-};
-
-static DupKey GetDupKey(const llvm::APSInt& Val) {
- return DupKey(Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(),
- false);
-}
-
-struct DenseMapInfoDupKey {
- static DupKey getEmptyKey() { return DupKey(0, true); }
- static DupKey getTombstoneKey() { return DupKey(1, true); }
- static unsigned getHashValue(const DupKey Key) {
- return (unsigned)(Key.val * 37);
- }
- static bool isEqual(const DupKey& LHS, const DupKey& RHS) {
- return LHS.isTombstoneOrEmptyKey == RHS.isTombstoneOrEmptyKey &&
- LHS.val == RHS.val;
- }
-};
-
-// Emits a warning when an element is implicitly set a value that
-// a previous element has already been set to.
-static void CheckForDuplicateEnumValues(Sema &S, Decl **Elements,
- unsigned NumElements, EnumDecl *Enum,
- QualType EnumType) {
- if (S.Diags.getDiagnosticLevel(diag::warn_duplicate_enum_values,
- Enum->getLocation()) ==
- DiagnosticsEngine::Ignored)
- return;
- // Avoid anonymous enums
- if (!Enum->getIdentifier())
- return;
-
- // Only check for small enums.
- if (Enum->getNumPositiveBits() > 63 || Enum->getNumNegativeBits() > 64)
- return;
-
- typedef llvm::SmallVector<EnumConstantDecl*, 3> ECDVector;
- typedef llvm::SmallVector<ECDVector*, 3> DuplicatesVector;
-
- typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector;
- typedef llvm::DenseMap<DupKey, DeclOrVector, DenseMapInfoDupKey>
- ValueToVectorMap;
-
- DuplicatesVector DupVector;
- ValueToVectorMap EnumMap;
-
- // Populate the EnumMap with all values represented by enum constants without
- // an initialier.
- for (unsigned i = 0; i < NumElements; ++i) {
- EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
-
- // Null EnumConstantDecl means a previous diagnostic has been emitted for
- // this constant. Skip this enum since it may be ill-formed.
- if (!ECD) {
- return;
- }
-
- if (ECD->getInitExpr())
- continue;
-
- DupKey Key = GetDupKey(ECD->getInitVal());
- DeclOrVector &Entry = EnumMap[Key];
-
- // First time encountering this value.
- if (Entry.isNull())
- Entry = ECD;
- }
-
- // Create vectors for any values that has duplicates.
- for (unsigned i = 0; i < NumElements; ++i) {
- EnumConstantDecl *ECD = cast<EnumConstantDecl>(Elements[i]);
- if (!ValidDuplicateEnum(ECD, Enum))
- continue;
-
- DupKey Key = GetDupKey(ECD->getInitVal());
-
- DeclOrVector& Entry = EnumMap[Key];
- if (Entry.isNull())
- continue;
-
- if (EnumConstantDecl *D = Entry.dyn_cast<EnumConstantDecl*>()) {
- // Ensure constants are different.
- if (D == ECD)
- continue;
-
- // Create new vector and push values onto it.
- ECDVector *Vec = new ECDVector();
- Vec->push_back(D);
- Vec->push_back(ECD);
-
- // Update entry to point to the duplicates vector.
- Entry = Vec;
-
- // Store the vector somewhere we can consult later for quick emission of
- // diagnostics.
- DupVector.push_back(Vec);
- continue;
- }
-
- ECDVector *Vec = Entry.get<ECDVector*>();
- // Make sure constants are not added more than once.
- if (*Vec->begin() == ECD)
- continue;
-
- Vec->push_back(ECD);
- }
-
- // Emit diagnostics.
- for (DuplicatesVector::iterator DupVectorIter = DupVector.begin(),
- DupVectorEnd = DupVector.end();
- DupVectorIter != DupVectorEnd; ++DupVectorIter) {
- ECDVector *Vec = *DupVectorIter;
- assert(Vec->size() > 1 && "ECDVector should have at least 2 elements.");
-
- // Emit warning for one enum constant.
- ECDVector::iterator I = Vec->begin();
- S.Diag((*I)->getLocation(), diag::warn_duplicate_enum_values)
- << (*I)->getName() << (*I)->getInitVal().toString(10)
- << (*I)->getSourceRange();
- ++I;
-
- // Emit one note for each of the remaining enum constants with
- // the same value.
- for (ECDVector::iterator E = Vec->end(); I != E; ++I)
- S.Diag((*I)->getLocation(), diag::note_duplicate_element)
- << (*I)->getName() << (*I)->getInitVal().toString(10)
- << (*I)->getSourceRange();
- delete Vec;
- }
-}
-
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
SourceLocation RBraceLoc, Decl *EnumDeclX,
Decl **Elements, unsigned NumElements,
// it needs to go into the function scope.
if (InFunctionDeclarator)
DeclsInPrototypeScope.push_back(Enum);
-
- CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
- CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
}
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,