[Clang] Fix an unused-but-set-variable warning with volatile variable
authorYonghong Song <yhs@fb.com>
Sat, 12 Mar 2022 19:05:40 +0000 (11:05 -0800)
committerYonghong Song <yhs@fb.com>
Mon, 21 Mar 2022 21:59:03 +0000 (14:59 -0700)
For the following code,
    void test() {
        volatile int j = 0;
        for (int i = 0; i < 1000; i++)
                j += 1;
        return;
    }
If compiled with
    clang -g -Wall -Werror -S -emit-llvm test.c
we will see the following error:
    test.c:2:6: error: variable 'j' set but not used [-Werror,-Wunused-but-set-variable]
            volatile int j = 0;
                         ^

This is not quite right since 'j' is indeed used due to '+=' operator.
gcc doesn't emit error either in this case.
Also if we change 'j += 1' to 'j++', the warning will disappear
with latest clang.

Note that clang will issue the warning if the volatile declaration
involves only simple assignment (var = ...).

To fix the issue, in function MaybeDecrementCount(), if the
operator is a compound assignment (i.e., +=, -=, etc.) and the
variable is volatile, the count for RefsMinusAssignments will be
decremented, similar to 'j++' case.

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

clang/lib/Sema/SemaExprCXX.cpp
clang/test/Sema/warn-unused-but-set-variables.c

index ee4bff5..c923ddd 100644 (file)
@@ -7925,6 +7925,7 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation,
 static void MaybeDecrementCount(
     Expr *E, llvm::DenseMap<const VarDecl *, int> &RefsMinusAssignments) {
   DeclRefExpr *LHS = nullptr;
+  bool IsCompoundAssign = false;
   if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
     if (BO->getLHS()->getType()->isDependentType() ||
         BO->getRHS()->getType()->isDependentType()) {
@@ -7932,6 +7933,8 @@ static void MaybeDecrementCount(
         return;
     } else if (!BO->isAssignmentOp())
       return;
+    else
+      IsCompoundAssign = BO->isCompoundAssignmentOp();
     LHS = dyn_cast<DeclRefExpr>(BO->getLHS());
   } else if (CXXOperatorCallExpr *COCE = dyn_cast<CXXOperatorCallExpr>(E)) {
     if (COCE->getOperator() != OO_Equal)
@@ -7943,6 +7946,10 @@ static void MaybeDecrementCount(
   VarDecl *VD = dyn_cast<VarDecl>(LHS->getDecl());
   if (!VD)
     return;
+  // Don't decrement RefsMinusAssignments if volatile variable with compound
+  // assignment (+=, ...) to avoid potential unused-but-set-variable warning.
+  if (IsCompoundAssign && VD->getType().isVolatileQualified())
+    return;
   auto iter = RefsMinusAssignments.find(VD);
   if (iter == RefsMinusAssignments.end())
     return;
index a8d2cea..6e5b7d6 100644 (file)
@@ -23,10 +23,24 @@ int f0(void) {
   int a;
   w = (a = 0);
 
+  int j = 0; // expected-warning{{variable 'j' set but not used}}
+  for (int i = 0; i < 1000; i++)
+    j += 1;
+
   // Following gcc, warn for a volatile variable.
   volatile int b; // expected-warning{{variable 'b' set but not used}}
   b = 0;
 
+  // volatile variable k is used, no warning.
+  volatile int k = 0;
+  for (int i = 0; i < 1000; i++)
+    k += 1;
+
+  // typedef of volatile type, no warning.
+  typedef volatile int volint;
+  volint l = 0;
+  l += 1;
+
   int x;
   x = 0;
   return x;