Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -337,6 +337,10 @@ can be controlled using ``-fcaret-diagnostics-max-lines=``. - Clang no longer emits ``-Wunused-variable`` warnings for variables declared with ``__attribute__((cleanup(...)))`` to match GCC's behavior. +- Clang now warns on unused variables declaread and initialized in condition + expressions. + (`#61681: `_) + Bug Fixes in This Version ------------------------- Index: clang/include/clang/AST/DeclBase.h =================================================================== --- clang/include/clang/AST/DeclBase.h +++ clang/include/clang/AST/DeclBase.h @@ -588,7 +588,7 @@ /// /// This should only be used immediately after creating a declaration. /// It intentionally doesn't notify any listeners. - void setIsUsed() { getCanonicalDecl()->Used = true; } + void setIsUsed(bool U = true) { getCanonicalDecl()->Used = U; } /// Mark the declaration used, in the sense of odr-use. /// Index: clang/lib/CodeGen/CGExpr.cpp =================================================================== --- clang/lib/CodeGen/CGExpr.cpp +++ clang/lib/CodeGen/CGExpr.cpp @@ -2843,13 +2843,6 @@ } } - // FIXME: We should be able to assert this for FunctionDecls as well! - // FIXME: We should be able to assert this for all DeclRefExprs, not just - // those with a valid source location. - assert((ND->isUsed(false) || !isa(ND) || E->isNonOdrUse() || - !E->getLocation().isValid()) && - "Should not use decl without marking it used!"); - if (ND->hasAttr()) { const auto *VD = cast(ND); ConstantAddress Aliasee = CGM.GetWeakRefReference(VD); Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -3998,6 +3998,11 @@ ConditionVar, ConditionVar->getType().getNonReferenceType(), VK_LValue, ConditionVar->getLocation()); + // Ensure that `-Wunused-variable` will be emitted for condition variables + // that are not referenced or used later. e.g.: if (int var = init()); + ConditionVar->setReferenced(false); + ConditionVar->setIsUsed(false); + switch (CK) { case ConditionKind::Boolean: return CheckBooleanCondition(StmtLoc, Condition.get()); Index: clang/test/AST/ast-dump-if-json.cpp =================================================================== --- clang/test/AST/ast-dump-if-json.cpp +++ clang/test/AST/ast-dump-if-json.cpp @@ -709,7 +709,6 @@ // CHECK-NEXT: "tokLen": 2 // CHECK-NEXT: } // CHECK-NEXT: }, -// CHECK-NEXT: "isUsed": true, // CHECK-NEXT: "name": "i", // CHECK-NEXT: "type": { // CHECK-NEXT: "qualType": "int" Index: clang/test/AST/ast-dump-stmt-json.cpp =================================================================== --- clang/test/AST/ast-dump-stmt-json.cpp +++ clang/test/AST/ast-dump-stmt-json.cpp @@ -4167,7 +4167,6 @@ // CHECK-NEXT: "tokLen": 1 // CHECK-NEXT: } // CHECK-NEXT: }, -// CHECK-NEXT: "isUsed": true, // CHECK-NEXT: "name": "j", // CHECK-NEXT: "type": { // CHECK-NEXT: "qualType": "int" Index: clang/test/AST/ast-dump-stmt.cpp =================================================================== --- clang/test/AST/ast-dump-stmt.cpp +++ clang/test/AST/ast-dump-stmt.cpp @@ -179,7 +179,7 @@ // CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:12 used i 'int' cinit // CHECK-NEXT: IntegerLiteral 0x{{[^ ]*}} 'int' 0 // CHECK-NEXT: DeclStmt - // CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:23 used j 'int' cinit + // CHECK-NEXT: VarDecl 0x{{[^ ]*}} col:23 j 'int' cinit // CHECK-NEXT: ImplicitCastExpr // CHECK-NEXT: DeclRefExpr 0x{{[^ ]*}} 'int' lvalue Var 0x{{[^ ]*}} 'i' 'int' // CHECK-NEXT: ImplicitCastExpr 0x{{[^ ]*}} 'bool' Index: clang/test/SemaCXX/warn-unused-variables.cpp =================================================================== --- clang/test/SemaCXX/warn-unused-variables.cpp +++ clang/test/SemaCXX/warn-unused-variables.cpp @@ -1,5 +1,5 @@ // RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify %s -// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify -std=c++11 %s +// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -Wno-c++1z-extensions -verify -std=c++11 %s template void f() { T t; t = 17; @@ -294,3 +294,36 @@ } } // namespace gh54489 + +namespace inside_condition { + void ifs() { + if (int hoge = 0) // expected-warning {{unused variable 'hoge'}} + return; + if (const int const_hoge = 0) // expected-warning {{unused variable 'const_hoge'}} + return; + else if (int fuga = 0) + (void)fuga; + else if (int used = 1; int catched = used) // expected-warning {{unused variable 'catched'}} + return; + else if (int refed = 1; int used = refed) + (void)used; + else if (int unused1 = 2; int unused2 = 3) // expected-warning {{unused variable 'unused1'}} \ + // expected-warning {{unused variable 'unused2'}} + return; + else if (int unused = 4; int used = 5) // expected-warning {{unused variable 'unused'}} + (void)used; + else if (int used = 6; int unused = 7) // expected-warning {{unused variable 'unused'}} + (void)used; + else if (int used1 = 8; int used2 = 9) + (void)(used1 + used2); + } + + void fors() { + for (int i = 0;int unused = 0;); // expected-warning {{unused variable 'i'}} \ + // expected-warning {{unused variable 'unused'}} + for (int i = 0;int used = 0;) // expected-warning {{unused variable 'i'}} + (void)used; + while(int var = 1) // expected-warning {{unused variable 'var'}} + return; + } +} // namespace inside_condition