frederic-tingaud-sonarsource created this revision.
frederic-tingaud-sonarsource added a reviewer: dcoughlin.
Herald added a subscriber: martong.
Herald added a project: All.
frederic-tingaud-sonarsource requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

Dead store detection automatically checks that an expression is a 
CXXConstructor and skips it because of potential side effects. In C++17, with 
guaranteed copy elision, this check can fail because we actually receive the 
implicit cast of a CXXConstructor.
Most checks in the dead store analysis were already stripping all casts and 
parenthesis and those that weren't were either forgotten (like the constructor) 
or would not suffer from it, so this patch proposes to factorize the stripping.
It has an impact on where the dead store warning is reported in the case of an 
explicit cast, from

  auto a = static_cast<B>(A());
           ^~~~~~~~~~~~~~~~~~~

to

  auto a = static_cast<B>(A());
                          ^~~

which we think is an improvement.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D126534

Files:
  clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
  clang/test/Analysis/Inputs/expected-plists/objc-arc.m.plist
  clang/test/Analysis/dead-stores.cpp

Index: clang/test/Analysis/dead-stores.cpp
===================================================================
--- clang/test/Analysis/dead-stores.cpp
+++ clang/test/Analysis/dead-stores.cpp
@@ -12,6 +12,10 @@
 // RUN:  -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code            \
 // RUN:  -verify=non-nested,nested %s
 
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -fexceptions -fblocks -std=c++17    \
+// RUN:  -analyzer-checker=deadcode.DeadStores -Wno-unreachable-code            \
+// RUN:  -verify=non-nested,nested %s
+
 //===----------------------------------------------------------------------===//
 // Basic dead store checking (but in C++ mode).
 //===----------------------------------------------------------------------===//
@@ -52,6 +56,17 @@
   return x;
 }
 
+class TestConstructor {
+public:
+  TestConstructor(int &y);
+};
+void copy(int x) {
+  TestConstructor tc1 = x; // no-warning
+  TestConstructor tc2 = TestConstructor(x);   // no-warning
+  TestConstructor tc3 = (TestConstructor(x)); // no-warning
+  TestConstructor tc4 = (TestConstructor)(x); // no-warning
+}
+
 //===----------------------------------------------------------------------===//
 // Dead store checking involving CXXTemporaryExprs
 //===----------------------------------------------------------------------===//
Index: clang/test/Analysis/Inputs/expected-plists/objc-arc.m.plist
===================================================================
--- clang/test/Analysis/Inputs/expected-plists/objc-arc.m.plist
+++ clang/test/Analysis/Inputs/expected-plists/objc-arc.m.plist
@@ -432,7 +432,7 @@
        <array>
         <dict>
          <key>line</key><integer>139</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>35</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -500,7 +500,7 @@
        <array>
         <dict>
          <key>line</key><integer>144</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>33</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -568,7 +568,7 @@
        <array>
         <dict>
          <key>line</key><integer>145</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>26</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -636,7 +636,7 @@
        <array>
         <dict>
          <key>line</key><integer>146</integer>
-         <key>col</key><integer>13</integer>
+         <key>col</key><integer>33</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -1046,7 +1046,7 @@
        <array>
         <dict>
          <key>line</key><integer>150</integer>
-         <key>col</key><integer>19</integer>
+         <key>col</key><integer>48</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -1114,7 +1114,7 @@
        <array>
         <dict>
          <key>line</key><integer>151</integer>
-         <key>col</key><integer>21</integer>
+         <key>col</key><integer>52</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -1182,7 +1182,7 @@
        <array>
         <dict>
          <key>line</key><integer>152</integer>
-         <key>col</key><integer>19</integer>
+         <key>col</key><integer>39</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
@@ -1250,7 +1250,7 @@
        <array>
         <dict>
          <key>line</key><integer>153</integer>
-         <key>col</key><integer>21</integer>
+         <key>col</key><integer>43</integer>
          <key>file</key><integer>0</integer>
         </dict>
         <dict>
Index: clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/DeadStoresChecker.cpp
@@ -103,8 +103,9 @@
 static const Expr *
 LookThroughTransitiveAssignmentsAndCommaOperators(const Expr *Ex) {
   while (Ex) {
+    Ex = Ex->IgnoreParenCasts();
     const BinaryOperator *BO =
-      dyn_cast<BinaryOperator>(Ex->IgnoreParenCasts());
+      dyn_cast<BinaryOperator>(Ex);
     if (!BO)
       break;
     BinaryOperatorKind Op = BO->getOpcode();
@@ -332,7 +333,6 @@
           //  This is a common form of defensive programming.
           const Expr *RHS =
             LookThroughTransitiveAssignmentsAndCommaOperators(B->getRHS());
-          RHS = RHS->IgnoreParenCasts();
 
           QualType T = VD->getType();
           if (T.isVolatileQualified())
@@ -416,7 +416,7 @@
                 return;
 
               if (const DeclRefExpr *DRE =
-                      dyn_cast<DeclRefExpr>(E->IgnoreParenCasts()))
+                      dyn_cast<DeclRefExpr>(E))
                 if (const VarDecl *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
                   // Special case: check for initialization from constant
                   //  variables.
@@ -450,8 +450,9 @@
   bool isConstant(const InitListExpr *Candidate) const {
     // We consider init list to be constant if each member of the list can be
     // interpreted as constant.
-    return llvm::all_of(Candidate->inits(),
-                        [this](const Expr *Init) { return isConstant(Init); });
+    return llvm::all_of(Candidate->inits(), [this](const Expr *Init) {
+      return isConstant(Init->IgnoreParenCasts());
+    });
   }
 
   /// Return true if the given expression can be interpreted as constant
@@ -461,7 +462,7 @@
       return true;
 
     // We should also allow defensive initialization of structs, i.e. { 0 }
-    if (const auto *ILE = dyn_cast<InitListExpr>(E->IgnoreParenCasts())) {
+    if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
       return isConstant(ILE);
     }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to