diff options
author | David Bolvansky <david.bolvansky@gmail.com> | 2019-08-18 19:14:14 +0000 |
---|---|---|
committer | David Bolvansky <david.bolvansky@gmail.com> | 2019-08-18 19:14:14 +0000 |
commit | 920890e26812f808a74c60ebc14cc636dac661c1 (patch) | |
tree | e4ea00cd262c5410780b19d10c72082280980507 /clang/lib/Sema/SemaExpr.cpp | |
parent | c944438dfdbd6de9785f4652244e80d194f40b92 (diff) | |
download | bcm5719-llvm-920890e26812f808a74c60ebc14cc636dac661c1.tar.gz bcm5719-llvm-920890e26812f808a74c60ebc14cc636dac661c1.zip |
[Diagnostics] Diagnose misused xor as pow
Summary:
Motivation:
https://twitter.com/jfbastien/status/1139298419988549632
https://twitter.com/mikemx7f/status/1139335901790625793
https://codesearch.isocpp.org/cgi-bin/cgi_ppsearch?q=10+%5E&search=Search
Reviewers: jfb, rsmith, regehr, aaron.ballman
Reviewed By: aaron.ballman
Subscribers: lebedev.ri, Quuxplusone, erik.pilkington, riccibruno, dexonsmith, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D63423
llvm-svn: 369217
Diffstat (limited to 'clang/lib/Sema/SemaExpr.cpp')
-rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 106 |
1 files changed, 105 insertions, 1 deletions
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index b218ad1f66c..e2ff34a8a79 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11011,6 +11011,107 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, return GetSignedVectorType(vType); } +static void diagnoseXorMisusedAsPow(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc) { + // Do not diagnose macros. + if (Loc.isMacroID()) + return; + + bool Negative = false; + const auto *LHSInt = dyn_cast<IntegerLiteral>(LHS.get()); + const auto *RHSInt = dyn_cast<IntegerLiteral>(RHS.get()); + + if (!LHSInt) + return; + if (!RHSInt) { + // Check negative literals. + if (const auto *UO = dyn_cast<UnaryOperator>(RHS.get())) { + if (UO->getOpcode() != UO_Minus) + return; + RHSInt = dyn_cast<IntegerLiteral>(UO->getSubExpr()); + if (!RHSInt) + return; + Negative = true; + } else { + return; + } + } + + if (LHSInt->getValue().getBitWidth() != RHSInt->getValue().getBitWidth()) + return; + + CharSourceRange ExprRange = CharSourceRange::getCharRange( + LHSInt->getBeginLoc(), S.getLocForEndOfToken(RHSInt->getLocation())); + llvm::StringRef ExprStr = + Lexer::getSourceText(ExprRange, S.getSourceManager(), S.getLangOpts()); + + CharSourceRange XorRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + llvm::StringRef XorStr = + Lexer::getSourceText(XorRange, S.getSourceManager(), S.getLangOpts()); + // Do not diagnose if xor keyword/macro is used. + if (XorStr == "xor") + return; + + const llvm::APInt &LeftSideValue = LHSInt->getValue(); + const llvm::APInt &RightSideValue = RHSInt->getValue(); + const llvm::APInt XorValue = LeftSideValue ^ RightSideValue; + + std::string LHSStr = Lexer::getSourceText( + CharSourceRange::getTokenRange(LHSInt->getSourceRange()), + S.getSourceManager(), S.getLangOpts()); + std::string RHSStr = Lexer::getSourceText( + CharSourceRange::getTokenRange(RHSInt->getSourceRange()), + S.getSourceManager(), S.getLangOpts()); + + int64_t RightSideIntValue = RightSideValue.getSExtValue(); + if (Negative) { + RightSideIntValue = -RightSideIntValue; + RHSStr = "-" + RHSStr; + } + + StringRef LHSStrRef = LHSStr; + StringRef RHSStrRef = RHSStr; + // Do not diagnose binary, hexadecimal, octal literals. + if (LHSStrRef.startswith("0b") || LHSStrRef.startswith("0B") || + RHSStrRef.startswith("0b") || RHSStrRef.startswith("0B") || + LHSStrRef.startswith("0x") || LHSStrRef.startswith("0X") || + RHSStrRef.startswith("0x") || RHSStrRef.startswith("0X") || + (LHSStrRef.size() > 1 && LHSStrRef.startswith("0")) || + (RHSStrRef.size() > 1 && RHSStrRef.startswith("0"))) + return; + + if (LeftSideValue == 2 && RightSideIntValue >= 0) { + std::string SuggestedExpr = "1 << " + RHSStr; + bool Overflow = false; + llvm::APInt One = (LeftSideValue - 1); + llvm::APInt PowValue = One.sshl_ov(RightSideValue, Overflow); + if (Overflow) { + if (RightSideIntValue < 64) + S.Diag(Loc, diag::warn_xor_used_as_pow_base) + << ExprStr << XorValue.toString(10, true) << ("1LL << " + RHSStr) + << FixItHint::CreateReplacement(ExprRange, "1LL << " + RHSStr); + else + // TODO: 2 ^ 64 - 1 + return; + } else { + S.Diag(Loc, diag::warn_xor_used_as_pow_base_extra) + << ExprStr << XorValue.toString(10, true) << SuggestedExpr + << PowValue.toString(10, true) + << FixItHint::CreateReplacement( + ExprRange, (RightSideIntValue == 0) ? "1" : SuggestedExpr); + } + + S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0x2 ^ " + RHSStr); + } else if (LeftSideValue == 10) { + std::string SuggestedValue = "1e" + std::to_string(RightSideIntValue); + S.Diag(Loc, diag::warn_xor_used_as_pow_base) + << ExprStr << XorValue.toString(10, true) << SuggestedValue + << FixItHint::CreateReplacement(ExprRange, SuggestedValue); + S.Diag(Loc, diag::note_xor_used_as_pow_silence) << ("0xA ^ " + RHSStr); + } +} + QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { // Ensure that either both operands are of the same vector type, or @@ -11054,6 +11155,9 @@ inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, if (Opc == BO_And) diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + if (Opc == BO_Xor) + diagnoseXorMisusedAsPow(*this, LHS, RHS, Loc); + ExprResult LHSResult = LHS, RHSResult = RHS; QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, IsCompAssign); @@ -17640,4 +17744,4 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); -} +}
\ No newline at end of file |