Skip to content

Commit ca1aaac

Browse files
committedOct 21, 2017
[Sema] Fixes for enum handling for tautological comparison diagnostics
Summary: As Mattias Eriksson has reported in PR35009, in C, for enums, the underlying type should be used when checking for the tautological comparison, unlike C++, where the enumerator values define the value range. So if not in CPlusPlus mode, use the enum underlying type. Also, i have discovered a problem (a crash) when evaluating tautological-ness of the following comparison: ``` enum A { A_a = 0 }; if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; ``` This affects both the C and C++, but after the first fix, only C++ code was affected. That was also fixed, while preserving (i think?) the proper diagnostic output. And while there, attempt to enhance the test coverage. Yes, some tests got moved around, sorry about that :) Fixes PR35009 Reviewers: aaron.ballman, rsmith, rjmccall Reviewed By: aaron.ballman Subscribers: Rakete1111, efriedma, materi, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D39122 llvm-svn: 316268
1 parent f45629d commit ca1aaac

5 files changed

+1232
-58
lines changed
 

‎clang/lib/Sema/SemaChecking.cpp

+21-8
Original file line numberDiff line numberDiff line change
@@ -8181,8 +8181,12 @@ struct IntRange {
81818181
if (const AtomicType *AT = dyn_cast<AtomicType>(T))
81828182
T = AT->getValueType().getTypePtr();
81838183

8184-
// For enum types, use the known bit width of the enumerators.
8185-
if (const EnumType *ET = dyn_cast<EnumType>(T)) {
8184+
if (!C.getLangOpts().CPlusPlus) {
8185+
// For enum types in C code, use the underlying datatype.
8186+
if (const EnumType *ET = dyn_cast<EnumType>(T))
8187+
T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr();
8188+
} else if (const EnumType *ET = dyn_cast<EnumType>(T)) {
8189+
// For enum types in C++, use the known bit width of the enumerators.
81868190
EnumDecl *Enum = ET->getDecl();
81878191
// In C++11, enums without definitions can have an explicitly specified
81888192
// underlying type. Use this type to compute the range.
@@ -8584,8 +8588,10 @@ bool isNonBooleanUnsignedValue(Expr *E) {
85848588
}
85858589

85868590
enum class LimitType {
8587-
Max, // e.g. 32767 for short
8588-
Min // e.g. -32768 for short
8591+
Max = 1U << 0U, // e.g. 32767 for short
8592+
Min = 1U << 1U, // e.g. -32768 for short
8593+
Both = Max | Min // When the value is both the Min and the Max limit at the
8594+
// same time; e.g. in C++, A::a in enum A { a = 0 };
85898595
};
85908596

85918597
/// Checks whether Expr 'Constant' may be the
@@ -8608,6 +8614,10 @@ llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other,
86088614

86098615
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
86108616

8617+
// Special-case for C++ for enum with one enumerator with value of 0.
8618+
if (OtherRange.Width == 0)
8619+
return Value == 0 ? LimitType::Both : llvm::Optional<LimitType>();
8620+
86118621
if (llvm::APSInt::isSameValue(
86128622
llvm::APSInt::getMaxValue(OtherRange.Width,
86138623
OtherT->isUnsignedIntegerType()),
@@ -8620,7 +8630,7 @@ llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other,
86208630
Value))
86218631
return LimitType::Min;
86228632

8623-
return llvm::Optional<LimitType>();
8633+
return llvm::None;
86248634
}
86258635

86268636
bool HasEnumType(Expr *E) {
@@ -8655,9 +8665,12 @@ bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant,
86558665

86568666
bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant;
86578667
bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE);
8658-
bool ResultWhenConstNeOther =
8659-
ConstIsLowerBound ^ (ValueType == LimitType::Max);
8660-
if (ResultWhenConstEqualsOther != ResultWhenConstNeOther)
8668+
if (ValueType != LimitType::Both) {
8669+
bool ResultWhenConstNeOther =
8670+
ConstIsLowerBound ^ (ValueType == LimitType::Max);
8671+
if (ResultWhenConstEqualsOther != ResultWhenConstNeOther)
8672+
return false; // The comparison is not tautological.
8673+
} else if (ResultWhenConstEqualsOther == ConstIsLowerBound)
86618674
return false; // The comparison is not tautological.
86628675

86638676
const bool Result = ResultWhenConstEqualsOther;

0 commit comments

Comments
 (0)
Please sign in to comment.