diff options
author | Erik Pilkington <erik.pilkington@gmail.com> | 2019-07-08 23:42:52 +0000 |
---|---|---|
committer | Erik Pilkington <erik.pilkington@gmail.com> | 2019-07-08 23:42:52 +0000 |
commit | fa591c370d2417bd026294ccfa5b15b91e789078 (patch) | |
tree | 8d082b4d5e8edb50af883e99ba3f15c18a94a7aa /clang/lib | |
parent | accd3e87478eb75d455e016500ef3d2ddbeca82d (diff) | |
download | bcm5719-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.cpp | 36 |
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 |