[clang-tools-extra] r316767 - [clang-tidy] Fix bug 34845, offending standard bitmask types

Jonas Toth via cfe-commits cfe-commits at lists.llvm.org
Fri Oct 27 07:44:08 PDT 2017


Author: jonastoth
Date: Fri Oct 27 07:44:08 2017
New Revision: 316767

URL: http://llvm.org/viewvc/llvm-project?rev=316767&view=rev
Log:
[clang-tidy] Fix bug 34845, offending standard bitmask types

Summary:
The C++ standard allows implementations to choose the underlying type for
bitmask types (e.g. std::ios_base::openmode). MSVC implemented some of them
as signed integers resulting in warnings for usual code like
`auto dd = std::ios_base::badbit | std::ios_base::failbit;`

These false positives were reported in https://bugs.llvm.org/show_bug.cgi?id=34845

The fix allows bitwise |,&,^ for known standard bitmask types under the condition
that both operands are such bitmask types.
Shifting and bitwise complement are still forbidden.

Reviewers: aaron.ballman, alexfh, hokein

Reviewed By: aaron.ballman

Subscribers: xazax.hun

Differential Revision: https://reviews.llvm.org/D39099

Added:
    clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp
    clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.h
Modified:
    clang-tools-extra/trunk/clang-tidy/hicpp/SignedBitwiseCheck.cpp

Modified: clang-tools-extra/trunk/clang-tidy/hicpp/SignedBitwiseCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/hicpp/SignedBitwiseCheck.cpp?rev=316767&r1=316766&r2=316767&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/hicpp/SignedBitwiseCheck.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/hicpp/SignedBitwiseCheck.cpp Fri Oct 27 07:44:08 2017
@@ -20,34 +20,72 @@ namespace hicpp {
 
 void SignedBitwiseCheck::registerMatchers(MatchFinder *Finder) {
   const auto SignedIntegerOperand =
-      expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed_operand");
+      expr(ignoringImpCasts(hasType(isSignedInteger()))).bind("signed-operand");
+
+  // The standard [bitmask.types] allows some integral types to be implemented
+  // as signed types. Exclude these types from diagnosing for bitwise or(|) and
+  // bitwise and(&). Shifting and complementing such values is still not
+  // allowed.
+  const auto BitmaskType = namedDecl(anyOf(
+      hasName("::std::locale::category"), hasName("::std::ctype_base::mask"),
+      hasName("::std::ios_base::fmtflags"), hasName("::std::ios_base::iostate"),
+      hasName("::std::ios_base::openmode")));
+  const auto IsStdBitmask = ignoringImpCasts(declRefExpr(hasType(BitmaskType)));
 
   // Match binary bitwise operations on signed integer arguments.
   Finder->addMatcher(
-      binaryOperator(allOf(anyOf(hasOperatorName("|"), hasOperatorName("&"),
-                                 hasOperatorName("^"), hasOperatorName("<<"),
-                                 hasOperatorName(">>")),
+      binaryOperator(
+          allOf(anyOf(hasOperatorName("^"), hasOperatorName("|"),
+                      hasOperatorName("&")),
+
+                unless(allOf(hasLHS(IsStdBitmask), hasRHS(IsStdBitmask))),
+
+                hasEitherOperand(SignedIntegerOperand),
+                hasLHS(hasType(isInteger())), hasRHS(hasType(isInteger()))))
+          .bind("binary-no-sign-interference"),
+      this);
+
+  // Shifting and complement is not allowed for any signed integer type because
+  // the sign bit may corrupt the result.
+  Finder->addMatcher(
+      binaryOperator(allOf(anyOf(hasOperatorName("<<"), hasOperatorName(">>")),
                            hasEitherOperand(SignedIntegerOperand),
                            hasLHS(hasType(isInteger())),
                            hasRHS(hasType(isInteger()))))
-          .bind("binary_signed"),
+          .bind("binary-sign-interference"),
       this);
 
   // Match unary operations on signed integer types.
   Finder->addMatcher(unaryOperator(allOf(hasOperatorName("~"),
                                          hasUnaryOperand(SignedIntegerOperand)))
-                         .bind("unary_signed"),
+                         .bind("unary-signed"),
                      this);
 }
 
 void SignedBitwiseCheck::check(const MatchFinder::MatchResult &Result) {
   const ast_matchers::BoundNodes &N = Result.Nodes;
-  const auto *SignedBinary = N.getNodeAs<BinaryOperator>("binary_signed");
-  const auto *SignedUnary = N.getNodeAs<UnaryOperator>("unary_signed");
-  const auto *SignedOperand = N.getNodeAs<Expr>("signed_operand");
+  const auto *SignedOperand = N.getNodeAs<Expr>("signed-operand");
+  assert(SignedOperand &&
+         "No signed operand found in problematic bitwise operations");
+
+  bool IsUnary = false;
+  SourceLocation Location;
+
+  if (const auto *UnaryOp = N.getNodeAs<UnaryOperator>("unary-signed")) {
+    IsUnary = true;
+    Location = UnaryOp->getLocStart();
+  } else {
+    if (const auto *BinaryOp =
+            N.getNodeAs<BinaryOperator>("binary-no-sign-interference"))
+      Location = BinaryOp->getLocStart();
+    else if (const auto *BinaryOp =
+                 N.getNodeAs<BinaryOperator>("binary-sign-interference"))
+      Location = BinaryOp->getLocStart();
+    else
+      llvm_unreachable("unexpected matcher result");
+  }
 
-  const bool IsUnary = SignedUnary != nullptr;
-  diag(IsUnary ? SignedUnary->getLocStart() : SignedBinary->getLocStart(),
+  diag(Location,
        "use of a signed integer operand with a %select{binary|unary}0 bitwise "
        "operator")
       << IsUnary << SignedOperand->getSourceRange();

Added: clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp?rev=316767&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.cpp Fri Oct 27 07:44:08 2017
@@ -0,0 +1,188 @@
+// RUN: clang-tidy %s -checks='-*,hicpp-signed-bitwise' -- -std=c++11
+
+#include "hicpp-signed-bitwise-standard-types.h"
+
+void pure_bitmask_types() {
+  // std::locale::category
+  int SResult = 0;
+  std::locale::category C = std::locale::category::ctype;
+
+  SResult = std::locale::category::none | std::locale::category::collate;
+  SResult = std::locale::category::ctype & std::locale::category::monetary;
+  SResult = std::locale::category::numeric ^ std::locale::category::time;
+  SResult = std::locale::category::messages | std::locale::category::all;
+
+  SResult = std::locale::category::all & C;
+  SResult = std::locale::category::all | C;
+  SResult = std::locale::category::all ^ C;
+
+  // std::ctype_base::mask
+  std::ctype_base::mask M = std::ctype_base::mask::punct;
+
+  SResult = std::ctype_base::mask::space | std::ctype_base::mask::print;
+  SResult = std::ctype_base::mask::cntrl & std::ctype_base::mask::upper;
+  SResult = std::ctype_base::mask::lower ^ std::ctype_base::mask::alpha;
+  SResult = std::ctype_base::mask::digit | std::ctype_base::mask::punct;
+  SResult = std::ctype_base::mask::xdigit & std::ctype_base::mask::alnum;
+  SResult = std::ctype_base::mask::alnum ^ std::ctype_base::mask::graph;
+
+  SResult = std::ctype_base::mask::space & M;
+  SResult = std::ctype_base::mask::space | M;
+  SResult = std::ctype_base::mask::space ^ M;
+
+  // std::ios_base::fmtflags
+  std::ios_base::fmtflags F = std::ios_base::fmtflags::floatfield;
+
+  SResult = std::ios_base::fmtflags::dec | std::ios_base::fmtflags::oct;
+  SResult = std::ios_base::fmtflags::hex & std::ios_base::fmtflags::basefield;
+  SResult = std::ios_base::fmtflags::left ^ std::ios_base::fmtflags::right;
+  SResult = std::ios_base::fmtflags::internal | std::ios_base::fmtflags::adjustfield;
+  SResult = std::ios_base::fmtflags::scientific & std::ios_base::fmtflags::fixed;
+  SResult = std::ios_base::fmtflags::floatfield ^ std::ios_base::fmtflags::boolalpha;
+  SResult = std::ios_base::fmtflags::showbase | std::ios_base::fmtflags::showpoint;
+  SResult = std::ios_base::fmtflags::showpos & std::ios_base::fmtflags::skipws;
+  SResult = std::ios_base::fmtflags::unitbuf ^ std::ios_base::fmtflags::uppercase;
+
+  SResult = std::ios_base::fmtflags::unitbuf | F;
+  SResult = std::ios_base::fmtflags::unitbuf & F;
+  SResult = std::ios_base::fmtflags::unitbuf ^ F;
+
+  // std::ios_base::iostate
+  std::ios_base::iostate S = std::ios_base::iostate::goodbit;
+
+  SResult = std::ios_base::iostate::goodbit | std::ios_base::iostate::badbit;
+  SResult = std::ios_base::iostate::failbit & std::ios_base::iostate::eofbit;
+  SResult = std::ios_base::iostate::failbit ^ std::ios_base::iostate::eofbit;
+
+  SResult = std::ios_base::iostate::goodbit | S;
+  SResult = std::ios_base::iostate::goodbit & S;
+  SResult = std::ios_base::iostate::goodbit ^ S;
+
+  // std::ios_base::openmode
+  std::ios_base::openmode B = std::ios_base::openmode::binary;
+
+  SResult = std::ios_base::openmode::app | std::ios_base::openmode::binary;
+  SResult = std::ios_base::openmode::in & std::ios_base::openmode::out;
+  SResult = std::ios_base::openmode::trunc ^ std::ios_base::openmode::ate;
+
+  SResult = std::ios_base::openmode::trunc | B;
+  SResult = std::ios_base::openmode::trunc & B;
+  SResult = std::ios_base::openmode::trunc ^ B;
+}
+
+void still_forbidden() {
+  // std::locale::category
+  unsigned int UResult = 0u;
+  int SResult = 0;
+
+  SResult = std::ctype_base::mask::print ^ 8u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  SResult = std::ctype_base::mask::cntrl | 8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  SResult = std::ctype_base::mask::upper & 8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  SResult = std::ctype_base::mask::lower ^ -8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = std::locale::category::collate << 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::locale::category::ctype << 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::locale::category::monetary >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::locale::category::numeric >> 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = ~std::locale::category::messages;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+  SResult = ~std::locale::category::all;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+  // std::ctype_base::mask
+  UResult = std::ctype_base::mask::space | 8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ctype_base::mask::print & 8u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ctype_base::mask::cntrl ^ -8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = std::ctype_base::mask::upper << 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ctype_base::mask::lower << 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ctype_base::mask::alpha >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ctype_base::mask::digit >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = ~std::ctype_base::mask::punct;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+  SResult = ~std::ctype_base::mask::xdigit;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+  // std::ios_base::fmtflags
+  UResult = std::ios_base::fmtflags::dec | 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::fmtflags::oct & 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::fmtflags::hex ^ -1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = std::ios_base::fmtflags::basefield >> 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::fmtflags::left >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::fmtflags::right << 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::fmtflags::internal << 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = ~std::ios_base::fmtflags::adjustfield;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+  SResult = ~std::ios_base::fmtflags::scientific;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+  // std::ios_base::iostate
+  UResult = std::ios_base::iostate::goodbit | 8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::iostate::badbit & 8u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::iostate::failbit ^ -8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = std::ios_base::iostate::eofbit << 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::iostate::goodbit << 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::iostate::badbit >> 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::iostate::failbit >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = ~std::ios_base::iostate::eofbit;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+  SResult = ~std::ios_base::iostate::goodbit;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+
+  // std::ios_base::openmode
+  UResult = std::ios_base::app | 8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::binary & 8u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::in ^ -8;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = std::ios_base::out >> 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::trunc >> 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::ate << 1;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+  UResult = std::ios_base::ate << 1u;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a binary bitwise operator
+
+  UResult = ~std::ios_base::openmode::app;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+  SResult = ~std::ios_base::openmode::binary;
+  // CHECK-MESSAGES: [[@LINE-1]]:13: warning: use of a signed integer operand with a unary bitwise operator
+}

Added: clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.h?rev=316767&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.h (added)
+++ clang-tools-extra/trunk/test/clang-tidy/hicpp-signed-bitwise-standard-types.h Fri Oct 27 07:44:08 2017
@@ -0,0 +1,81 @@
+#pragma clang system_header
+
+// Implement standard types that are known to be defined as unsigned in some
+// implementations like MSVC.
+namespace std {
+namespace locale {
+enum category : int {
+  none = 0u,
+  collate = 1u << 1u,
+  ctype = 1u << 2u,
+  monetary = 1u << 3u,
+  numeric = 1u << 4u,
+  time = 1u << 5u,
+  messages = 1u << 6u,
+  all = none | collate | ctype | monetary | numeric | time | messages
+  // CHECK MESSAGES: [[@LINE-1]]:9: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace locale
+
+namespace ctype_base {
+enum mask : int {
+  space,
+  print,
+  cntrl,
+  upper,
+  lower,
+  alpha,
+  digit,
+  punct,
+  xdigit,
+  /* blank, // C++11 */
+  alnum = alpha | digit,
+  // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+  graph = alnum | punct
+  // CHECK MESSAGES: [[@LINE-1]]:11: warning: use of a signed integer operand with a binary bitwise operator
+};
+} // namespace ctype_base
+
+namespace ios_base {
+enum fmtflags : int {
+  dec = 0u,
+  oct = 1u << 2u,
+  hex = 1u << 3u,
+  basefield = dec | oct | hex | 0u,
+  // CHECK MESSAGES: [[@LINE-1]]:15: warning: use of a signed integer operand with a binary bitwise operator
+  left = 1u << 4u,
+  right = 1u << 5u,
+  internal = 1u << 6u,
+  adjustfield = left | right | internal,
+  // CHECK MESSAGES: [[@LINE-1]]:17: warning: use of a signed integer operand with a binary bitwise operator
+  scientific = 1u << 7u,
+  fixed = 1u << 8u,
+  floatfield = scientific | fixed | (scientific | fixed) | 0u,
+  // CHECK MESSAGES: [[@LINE-1]]:16: warning: use of a signed integer operand with a binary bitwise operator
+  // CHECK MESSAGES: [[@LINE-2]]:38: warning: use of a signed integer operand with a binary bitwise operator
+  boolalpha = 1u << 9u,
+  showbase = 1u << 10u,
+  showpoint = 1u << 11u,
+  showpos = 1u << 12u,
+  skipws = 1u << 13u,
+  unitbuf = 1u << 14u,
+  uppercase = 1u << 15u
+};
+
+enum iostate : int {
+  goodbit = 0u,
+  badbit = 1u << 1u,
+  failbit = 1u << 2u,
+  eofbit = 1u << 3u
+};
+
+enum openmode : int {
+  app = 0u,
+  binary = 0u << 1u,
+  in = 0u << 2u,
+  out = 0u << 3u,
+  trunc = 0u << 4u,
+  ate = 0u << 5u
+};
+} // namespace ios_base
+} // namespace std




More information about the cfe-commits mailing list