summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorErik Pilkington <erik.pilkington@gmail.com>2019-07-08 23:42:52 +0000
committerErik Pilkington <erik.pilkington@gmail.com>2019-07-08 23:42:52 +0000
commitfa591c370d2417bd026294ccfa5b15b91e789078 (patch)
tree8d082b4d5e8edb50af883e99ba3f15c18a94a7aa /clang/lib
parentaccd3e87478eb75d455e016500ef3d2ddbeca82d (diff)
downloadbcm5719-llvm-fa591c370d2417bd026294ccfa5b15b91e789078.tar.gz
bcm5719-llvm-fa591c370d2417bd026294ccfa5b15b91e789078.zip
[ObjC] Add a -Wtautological-compare warning for BOOL
On macOS, BOOL is a typedef for signed char, but it should never hold a value that isn't 1 or 0. Any code that expects a different value in their BOOL should be fixed. rdar://51954400 Differential revision: https://reviews.llvm.org/D63856 llvm-svn: 365408
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Sema/SemaChecking.cpp36
1 files changed, 30 insertions, 6 deletions
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 92951a8e3bd..702a2305968 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -10188,9 +10188,16 @@ static bool IsEnumConstOrFromMacro(Sema &S, Expr *E) {
if (isa<EnumConstantDecl>(DR->getDecl()))
return true;
- // Suppress cases where the '0' value is expanded from a macro.
- if (E->getBeginLoc().isMacroID())
- return true;
+ // Suppress cases where the value is expanded from a macro, unless that macro
+ // is how a language represents a boolean literal. This is the case in both C
+ // and Objective-C.
+ SourceLocation BeginLoc = E->getBeginLoc();
+ if (BeginLoc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroName(
+ BeginLoc, S.getSourceManager(), S.getLangOpts());
+ return MacroName != "YES" && MacroName != "NO" &&
+ MacroName != "true" && MacroName != "false";
+ }
return false;
}
@@ -10382,11 +10389,17 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
OtherT = AT->getValueType();
IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ // Special case for ObjC BOOL on targets where its a typedef for a signed char
+ // (Namely, macOS).
+ bool IsObjCSignedCharBool = S.getLangOpts().ObjC &&
+ S.NSAPIObj->isObjCBOOLType(OtherT) &&
+ OtherT->isSpecificBuiltinType(BuiltinType::SChar);
+
// Whether we're treating Other as being a bool because of the form of
// expression despite it having another type (typically 'int' in C).
bool OtherIsBooleanDespiteType =
!OtherT->isBooleanType() && Other->isKnownToHaveBooleanValue();
- if (OtherIsBooleanDespiteType)
+ if (OtherIsBooleanDespiteType || IsObjCSignedCharBool)
OtherRange = IntRange::forBoolType();
// Determine the promoted range of the other type and see if a comparison of
@@ -10417,10 +10430,21 @@ static bool CheckTautologicalComparison(Sema &S, BinaryOperator *E,
// Should be enough for uint128 (39 decimal digits)
SmallString<64> PrettySourceValue;
llvm::raw_svector_ostream OS(PrettySourceValue);
- if (ED)
+ if (ED) {
OS << '\'' << *ED << "' (" << Value << ")";
- else
+ } else if (auto *BL = dyn_cast<ObjCBoolLiteralExpr>(
+ Constant->IgnoreParenImpCasts())) {
+ OS << (BL->getValue() ? "YES" : "NO");
+ } else {
OS << Value;
+ }
+
+ if (IsObjCSignedCharBool) {
+ S.DiagRuntimeBehavior(E->getOperatorLoc(), E,
+ S.PDiag(diag::warn_tautological_compare_objc_bool)
+ << OS.str() << *Result);
+ return true;
+ }
// FIXME: We use a somewhat different formatting for the in-range cases and
// cases involving boolean values for historical reasons. We should pick a
OpenPOWER on IntegriCloud