forked from OSchip/llvm-project
Per discussion on cfe-dev, remove -Wunique-enums entirely. There
is no compelling argument that this is a generally useful warning, and imposes a strong stylistic argument on code beyond what it was intended to find warnings in. llvm-svn: 164083
This commit is contained in:
parent
dfc88a0338
commit
97c5a1e735
|
@ -20,17 +20,6 @@ def warn_variables_not_in_loop_body : Warning<
|
||||||
"used in loop condition not modified in loop body">,
|
"used in loop condition not modified in loop body">,
|
||||||
InGroup<DiagGroup<"loop-analysis">>, DefaultIgnore;
|
InGroup<DiagGroup<"loop-analysis">>, DefaultIgnore;
|
||||||
|
|
||||||
def warn_identical_enum_values : Warning<
|
|
||||||
"all elements of %0 are initialized with literals to value %1">,
|
|
||||||
InGroup<DiagGroup<"unique-enum">>;
|
|
||||||
def note_identical_enum_values : Note<
|
|
||||||
"initialize the last element with the previous element to silence "
|
|
||||||
"this warning">;
|
|
||||||
def warn_duplicate_enum_values : Warning<
|
|
||||||
"element %0 has been implicitly assigned %1 which another element has "
|
|
||||||
"been assigned">, InGroup<DiagGroup<"duplicate-enum">>, DefaultIgnore;
|
|
||||||
def note_duplicate_element : Note<"element %0 also has value %1">;
|
|
||||||
|
|
||||||
// Constant expressions
|
// Constant expressions
|
||||||
def err_expr_not_ice : Error<
|
def err_expr_not_ice : Error<
|
||||||
"expression is not an %select{integer|integral}0 constant expression">;
|
"expression is not an %select{integer|integral}0 constant expression">;
|
||||||
|
|
|
@ -10521,233 +10521,6 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
|
||||||
return New;
|
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,
|
void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
|
||||||
SourceLocation RBraceLoc, Decl *EnumDeclX,
|
SourceLocation RBraceLoc, Decl *EnumDeclX,
|
||||||
Decl **Elements, unsigned NumElements,
|
Decl **Elements, unsigned NumElements,
|
||||||
|
@ -10970,9 +10743,6 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
|
||||||
// it needs to go into the function scope.
|
// it needs to go into the function scope.
|
||||||
if (InFunctionDeclarator)
|
if (InFunctionDeclarator)
|
||||||
DeclsInPrototypeScope.push_back(Enum);
|
DeclsInPrototypeScope.push_back(Enum);
|
||||||
|
|
||||||
CheckForUniqueEnumValues(*this, Elements, NumElements, Enum, EnumType);
|
|
||||||
CheckForDuplicateEnumValues(*this, Elements, NumElements, Enum, EnumType);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
|
Decl *Sema::ActOnFileScopeAsmDecl(Expr *expr,
|
||||||
|
|
|
@ -1,92 +0,0 @@
|
||||||
// RUN: %clang_cc1 %s -fsyntax-only -verify -Wduplicate-enum
|
|
||||||
// RUN: %clang_cc1 %s -x c++ -fsyntax-only -verify -Wduplicate-enum
|
|
||||||
enum A {
|
|
||||||
A1 = 0, // expected-note {{element A1 also has value 0}}
|
|
||||||
A2 = -1,
|
|
||||||
A3, // expected-warning {{element A3 has been implicitly assigned 0 which another element has been assigned}}
|
|
||||||
A4};
|
|
||||||
|
|
||||||
enum B {
|
|
||||||
B1 = -1, // expected-note {{element B1 also has value -1}}
|
|
||||||
B2, // expected-warning {{element B2 has been implicitly assigned 0 which another element has been assigned}}
|
|
||||||
B3,
|
|
||||||
B4 = -2,
|
|
||||||
B5, // expected-warning {{element B5 has been implicitly assigned -1 which another element has been assigned}}
|
|
||||||
B6 // expected-note {{element B6 also has value 0}}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum C { C1, C2 = -1, C3 }; // expected-warning{{element C1 has been implicitly assigned 0 which another element has been assigned}} \
|
|
||||||
// expected-note {{element C3 also has value 0}}
|
|
||||||
|
|
||||||
enum D {
|
|
||||||
D1,
|
|
||||||
D2,
|
|
||||||
D3, // expected-warning{{element D3 has been implicitly assigned 2 which another element has been assigned}}
|
|
||||||
D4 = D2, // no warning
|
|
||||||
D5 = 2 // expected-note {{element D5 also has value 2}}
|
|
||||||
};
|
|
||||||
|
|
||||||
enum E {
|
|
||||||
E1,
|
|
||||||
E2 = E1,
|
|
||||||
E3 = E2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum F {
|
|
||||||
F1,
|
|
||||||
F2,
|
|
||||||
FCount,
|
|
||||||
FMax = FCount - 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum G {
|
|
||||||
G1,
|
|
||||||
G2,
|
|
||||||
GMax = G2,
|
|
||||||
GCount = GMax + 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
H1 = 0,
|
|
||||||
H2 = -1,
|
|
||||||
H3,
|
|
||||||
H4};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
I1 = -1,
|
|
||||||
I2,
|
|
||||||
I3,
|
|
||||||
I4 = -2,
|
|
||||||
I5,
|
|
||||||
I6
|
|
||||||
};
|
|
||||||
|
|
||||||
enum { J1, J2 = -1, J3 };
|
|
||||||
|
|
||||||
enum {
|
|
||||||
K1,
|
|
||||||
K2,
|
|
||||||
K3,
|
|
||||||
K4 = K2,
|
|
||||||
K5 = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
L1,
|
|
||||||
L2 = L1,
|
|
||||||
L3 = L2
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
M1,
|
|
||||||
M2,
|
|
||||||
MCount,
|
|
||||||
MMax = MCount - 1
|
|
||||||
};
|
|
||||||
|
|
||||||
enum {
|
|
||||||
N1,
|
|
||||||
N2,
|
|
||||||
NMax = N2,
|
|
||||||
NCount = NMax + 1
|
|
||||||
};
|
|
|
@ -1,27 +0,0 @@
|
||||||
// RUN: %clang_cc1 %s -fsyntax-only -verify -Wunique-enum
|
|
||||||
enum A { A1 = 1, A2 = 1, A3 = 1 }; // expected-warning {{all elements of 'A' are initialized with literals to value 1}} \
|
|
||||||
// expected-note {{initialize the last element with the previous element to silence this warning}}
|
|
||||||
enum { B1 = 1, B2 = 1, B3 = 1 }; // no warning
|
|
||||||
enum C { // expected-warning {{all elements of 'C' are initialized with literals to value 1}}
|
|
||||||
C1 = true,
|
|
||||||
C2 = true // expected-note {{initialize the last element with the previous element to silence this warning}}
|
|
||||||
};
|
|
||||||
enum D { D1 = 5, D2 = 5L, D3 = 5UL, D4 = 5LL, D5 = 5ULL }; // expected-warning {{all elements of 'D' are initialized with literals to value 5}} \
|
|
||||||
// expected-note {{initialize the last element with the previous element to silence this warning}}
|
|
||||||
|
|
||||||
// Don't warn on enums with less than 2 elements.
|
|
||||||
enum E { E1 = 4 };
|
|
||||||
enum F { F1 };
|
|
||||||
enum G {};
|
|
||||||
|
|
||||||
// Don't warn when integer literals do not initialize the elements.
|
|
||||||
enum H { H1 = 4, H_MAX = H1, H_MIN = H1 };
|
|
||||||
enum I { I1 = H1, I2 = 4 };
|
|
||||||
enum J { J1 = 4, J2 = I2 };
|
|
||||||
enum K { K1, K2, K3, K4 };
|
|
||||||
|
|
||||||
// Don't crash or warn on this one.
|
|
||||||
// rdar://11875995
|
|
||||||
enum L {
|
|
||||||
L1 = 0x8000000000000000ULL, L2 = 0x0000000000000001ULL
|
|
||||||
};
|
|
Loading…
Reference in New Issue