Index: clang/docs/ReleaseNotes.rst =================================================================== --- clang/docs/ReleaseNotes.rst +++ clang/docs/ReleaseNotes.rst @@ -132,6 +132,9 @@ of a base class is not called in the constructor of its derived class. - Clang no longer emits ``-Wmissing-variable-declarations`` for variables declared with the ``register`` storage class. +- Clang now warns on unused variables declared and initialized in condition + expressions. + (`#61681: `_) Bug Fixes in This Version ------------------------- Index: clang/include/clang/ASTMatchers/ASTMatchers.h =================================================================== --- clang/include/clang/ASTMatchers/ASTMatchers.h +++ clang/include/clang/ASTMatchers/ASTMatchers.h @@ -3928,7 +3928,7 @@ AST_POLYMORPHIC_MATCHER_P_OVERLOAD( callee, AST_POLYMORPHIC_SUPPORTED_TYPES(ObjCMessageExpr, CallExpr), internal::Matcher, InnerMatcher, 1) { - if (const auto *CallNode = dyn_cast(&Node)) + if (isa(&Node)) return callExpr(hasDeclaration(InnerMatcher)) .matches(Node, Finder, Builder); else { Index: clang/lib/AST/Interp/ByteCodeStmtGen.cpp =================================================================== --- clang/lib/AST/Interp/ByteCodeStmtGen.cpp +++ clang/lib/AST/Interp/ByteCodeStmtGen.cpp @@ -341,7 +341,7 @@ return IS->getElse() ? visitStmt(IS->getElse()) : true; if (auto *CondInit = IS->getInit()) - if (!visitStmt(IS->getInit())) + if (!visitStmt(CondInit)) return false; if (const DeclStmt *CondDecl = IS->getConditionVariableDeclStmt()) Index: clang/lib/CodeGen/BackendUtil.cpp =================================================================== --- clang/lib/CodeGen/BackendUtil.cpp +++ clang/lib/CodeGen/BackendUtil.cpp @@ -1353,7 +1353,7 @@ for (StringRef OffloadObject : CGOpts.OffloadObjects) { llvm::ErrorOr> ObjectOrErr = llvm::MemoryBuffer::getFileOrSTDIN(OffloadObject); - if (std::error_code EC = ObjectOrErr.getError()) { + if (ObjectOrErr.getError()) { auto DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "could not open '%0' for embedding"); Diags.Report(DiagID) << OffloadObject; Index: clang/lib/CodeGen/CGExprConstant.cpp =================================================================== --- clang/lib/CodeGen/CGExprConstant.cpp +++ clang/lib/CodeGen/CGExprConstant.cpp @@ -1132,7 +1132,7 @@ return CGM.GetAddrOfConstantStringFromLiteral(S).getPointer(); return nullptr; case CK_NullToPointer: - if (llvm::Constant *C = Visit(subExpr, destType)) + if (Visit(subExpr, destType)) return CGM.EmitNullConstant(destType); return nullptr; Index: clang/lib/CodeGen/CGOpenMPRuntime.cpp =================================================================== --- clang/lib/CodeGen/CGOpenMPRuntime.cpp +++ clang/lib/CodeGen/CGOpenMPRuntime.cpp @@ -1653,7 +1653,7 @@ PresumedLoc PLoc = SM.getPresumedLoc(BeginLoc); llvm::sys::fs::UniqueID ID; - if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { + if (llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { PLoc = SM.getPresumedLoc(BeginLoc, /*UseLineDirectives=*/false); } Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -7430,7 +7430,7 @@ // Get the UniqueID for the file containing the decl. llvm::sys::fs::UniqueID ID; - if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { + if (llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) { PLoc = SM.getPresumedLoc(D->getLocation(), /*UseLineDirectives=*/false); assert(PLoc.isValid() && "Source location is expected to be valid."); if (auto EC = llvm::sys::fs::getUniqueID(PLoc.getFilename(), ID)) Index: clang/lib/Driver/ToolChains/Cuda.cpp =================================================================== --- clang/lib/Driver/ToolChains/Cuda.cpp +++ clang/lib/Driver/ToolChains/Cuda.cpp @@ -629,8 +629,7 @@ const char *CubinF = Args.MakeArgString(getToolChain().getDriver().GetTemporaryPath( llvm::sys::path::stem(InputFile), "cubin")); - if (std::error_code EC = - llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF))) + if (llvm::sys::fs::copy_file(InputFile, C.addTempFile(CubinF))) continue; CmdArgs.push_back(CubinF); Index: clang/lib/Sema/SemaDecl.cpp =================================================================== --- clang/lib/Sema/SemaDecl.cpp +++ clang/lib/Sema/SemaDecl.cpp @@ -1995,7 +1995,7 @@ return false; } else if (!D->getDeclName()) { return false; - } else if (D->isReferenced() || D->isUsed()) { + } else if (D->isReferenced() || (!isa(D) && D->isUsed())) { return false; } Index: clang/lib/Sema/SemaExprCXX.cpp =================================================================== --- clang/lib/Sema/SemaExprCXX.cpp +++ clang/lib/Sema/SemaExprCXX.cpp @@ -4015,6 +4015,10 @@ ConditionVar, ConditionVar->getType().getNonReferenceType(), VK_LValue, ConditionVar->getLocation()); + // Ensure that `-Wunused-variable` will be emitted for condition variables + // that are not referenced later. e.g.: if (int var = init()); + ConditionVar->setReferenced(/*R=*/false); + switch (CK) { case ConditionKind::Boolean: return CheckBooleanCondition(StmtLoc, Condition.get()); Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -5352,7 +5352,7 @@ // will have been deferred. if (!NewVar->isInvalidDecl() && NewVar->getDeclContext()->isFunctionOrMethod() && - OldVar->getType()->isDependentType()) + OldVar->getType()->isDependentType() && !OldVar->isImplicit()) DiagnoseUnusedDecl(NewVar); } Index: clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp =================================================================== --- clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp +++ clang/lib/StaticAnalyzer/Checkers/FuchsiaHandleChecker.cpp @@ -381,7 +381,7 @@ SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); - if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) { + if (PathBR->getInterestingnessKind(RetSym)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Function '" << FuncDecl->getDeclName() @@ -397,7 +397,7 @@ SymbolRef RetSym = Call.getReturnValue().getAsSymbol(); Notes.push_back([RetSym, FuncDecl](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); - if (auto IsInteresting = PathBR->getInterestingnessKind(RetSym)) { + if (PathBR->getInterestingnessKind(RetSym)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Function '" << FuncDecl->getDeclName() @@ -431,7 +431,7 @@ } else { Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); - if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { + if (PathBR->getInterestingnessKind(Handle)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Handle released through " << ParamDiagIdx @@ -445,7 +445,7 @@ } else if (hasFuchsiaAttr(PVD)) { Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); - if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { + if (PathBR->getInterestingnessKind(Handle)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Handle allocated through " << ParamDiagIdx @@ -459,7 +459,7 @@ } else if (hasFuchsiaUnownedAttr(PVD)) { Notes.push_back([Handle, ParamDiagIdx](BugReport &BR) -> std::string { auto *PathBR = static_cast(&BR); - if (auto IsInteresting = PathBR->getInterestingnessKind(Handle)) { + if (PathBR->getInterestingnessKind(Handle)) { std::string SBuf; llvm::raw_string_ostream OS(SBuf); OS << "Unowned handle allocated through " << ParamDiagIdx Index: clang/lib/StaticAnalyzer/Checkers/Yaml.h =================================================================== --- clang/lib/StaticAnalyzer/Checkers/Yaml.h +++ clang/lib/StaticAnalyzer/Checkers/Yaml.h @@ -35,7 +35,7 @@ llvm::ErrorOr> Buffer = FS->getBufferForFile(ConfigFile.str()); - if (std::error_code ec = Buffer.getError()) { + if (Buffer.getError()) { Mgr.reportInvalidCheckerOptionValue(Chk, Option, "a valid filename instead of '" + std::string(ConfigFile) + "'"); 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++14-extensions -Wno-c++17-extensions -verify -std=c++11 %s template void f() { T t; t = 17; @@ -294,3 +294,115 @@ } } // 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); + else if (auto [a, b] = (int[2]){ 1, 2 }; 1) // expected-warning {{unused variable '[a, b]'}} + return; + else if (auto [a, b] = (int[2]){ 1, 2 }; a) + return; + } + + 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; + } + + void whiles() { + while(int unused = 1) // expected-warning {{unused variable 'unused'}} + return; + while(int used = 1) + (void)used; + } + + + void switches() { + switch(int unused = 1) { // expected-warning {{unused variable 'unused'}} + case 1: return; + } + switch(constexpr int used = 3; int unused = 4) { // expected-warning {{unused variable 'unused'}} + case used: return; + } + switch(int used = 3; int unused = 4) { // expected-warning {{unused variable 'unused'}} + case 3: (void)used; + } + switch(constexpr int used1 = 0; constexpr int used2 = 6) { + case (used1+used2): return; + } + switch(auto [a, b] = (int[2]){ 1, 2 }; 1) { // expected-warning {{unused variable '[a, b]'}} + case 1: return; + } + switch(auto [a, b] = (int[2]){ 1, 2 }; b) { + case 1: return; + } + switch(auto [a, b] = (int[2]){ 1, 2 }; 1) { + case 1: (void)a; + } + } + template + struct Vector { + void doIt() { + for (auto& e : elements){} // expected-warning {{unused variable 'e'}} + } + T elements[10]; + }; + void ranged_for() { + Vector vector; + vector.doIt(); // expected-note {{here}} + } + + + struct RAII { + int &x; + RAII(int &ref) : x(ref) {} + ~RAII() { x = 0;} + operator int() const { return 1; } + }; + void aggregate() { + int x = 10; + int y = 10; + if (RAII var = x) {} + for(RAII var = x; RAII var2 = y;) {} + while (RAII var = x) {} + switch (RAII var = x) {} + } + + struct TrivialDtor{ + int &x; + TrivialDtor(int &ref) : x(ref) { ref = 32; } + operator int() const { return 1; } + }; + void trivial_dtor() { + int x = 10; + int y = 10; + if (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}} + for(TrivialDtor var = x; TrivialDtor var2 = y;) {} // expected-warning {{unused variable 'var'}} \ + // expected-warning {{unused variable 'var2'}} + while (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}} + switch (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}} + } + +} // namespace inside_condition Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp =================================================================== --- clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -263,8 +263,8 @@ OutputFile.str(), ErrorFile.str(), }; - if (const int RC = llvm::sys::ExecuteAndWait( - ClangBinaryPath, PrintResourceDirArgs, {}, Redirects)) { + if (llvm::sys::ExecuteAndWait(ClangBinaryPath, PrintResourceDirArgs, {}, + Redirects)) { auto ErrorBuf = llvm::MemoryBuffer::getFile(ErrorFile.c_str()); llvm::errs() << ErrorBuf.get()->getBuffer(); return ""; Index: lld/MachO/Driver.cpp =================================================================== --- lld/MachO/Driver.cpp +++ lld/MachO/Driver.cpp @@ -311,7 +311,7 @@ path::filename(path).starts_with("libswift"); if ((isCommandLineLoad && config->allLoad) || loadType == LoadType::CommandLineForce || isLCLinkerForceLoad) { - if (std::optional buffer = readFile(path)) { + if (readFile(path)) { Error e = Error::success(); for (const object::Archive::Child &c : file->getArchive().children(e)) { StringRef reason; @@ -341,7 +341,7 @@ // TODO: no need to look for ObjC sections for a given archive member if // we already found that it contains an ObjC symbol. - if (std::optional buffer = readFile(path)) { + if (readFile(path)) { Error e = Error::success(); for (const object::Archive::Child &c : file->getArchive().children(e)) { Expected mb = c.getMemoryBufferRef(); Index: llvm/lib/Bitcode/Reader/MetadataLoader.cpp =================================================================== --- llvm/lib/Bitcode/Reader/MetadataLoader.cpp +++ llvm/lib/Bitcode/Reader/MetadataLoader.cpp @@ -555,12 +555,12 @@ if (!CU) continue; - if (auto *RawImported = CU->getRawImportedEntities()) { + if (CU->getRawImportedEntities()) { // Collect a set of imported entities to be moved. SetVector EntitiesToRemove; for (Metadata *Op : CU->getImportedEntities()->operands()) { auto *IE = cast(Op); - if (auto *S = dyn_cast_or_null(IE->getScope())) { + if (isa_and_present(IE->getScope())) { EntitiesToRemove.insert(IE); } } Index: llvm/lib/DebugInfo/DWARF/DWARFContext.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFContext.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFContext.cpp @@ -1187,7 +1187,7 @@ // So, we walk the CU's and their child DI's manually, looking for the // specific global variable. for (std::unique_ptr &CU : compile_units()) { - if (DWARFDie Die = CU->getVariableForAddress(Address)) { + if (CU->getVariableForAddress(Address)) { return static_cast(CU.get()); } } Index: llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp =================================================================== --- llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp +++ llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp @@ -828,7 +828,7 @@ // no type), then we use a size of one to still allow symbolization of the // exact address. uint64_t GVSize = 1; - if (DWARFDie BaseType = Die.getAttributeValueAsReferencedDie(DW_AT_type)) + if (Die.getAttributeValueAsReferencedDie(DW_AT_type)) if (std::optional Size = Die.getTypeSize(getAddressByteSize())) GVSize = *Size; Index: llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp =================================================================== --- llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp +++ llvm/lib/DebugInfo/GSYM/DwarfTransformer.cpp @@ -462,7 +462,7 @@ size_t NumBefore = Gsym.getNumFunctionInfos(); auto getDie = [&](DWARFUnit &DwarfUnit) -> DWARFDie { DWARFDie ReturnDie = DwarfUnit.getUnitDIE(false); - if (std::optional DWOId = DwarfUnit.getDWOId()) { + if (DwarfUnit.getDWOId()) { DWARFUnit *DWOCU = DwarfUnit.getNonSkeletonUnitDIE(false).getDwarfUnit(); if (OS && !DWOCU->isDWOUnit()) { std::string DWOName = dwarf::toString( Index: llvm/lib/IR/PrintPasses.cpp =================================================================== --- llvm/lib/IR/PrintPasses.cpp +++ llvm/lib/IR/PrintPasses.cpp @@ -212,7 +212,7 @@ static SmallVector FD{-1, -1, -1}; SmallVector SR{Before, After}; static SmallVector FileName{"", "", ""}; - if (auto Err = prepareTempFiles(FD, SR, FileName)) + if (prepareTempFiles(FD, SR, FileName)) return "Unable to create temporary file."; static ErrorOr DiffExe = sys::findProgramByName(DiffBinary); @@ -238,7 +238,7 @@ else return "Unable to read result."; - if (auto Err = cleanUpTempFiles(FileName)) + if (cleanUpTempFiles(FileName)) return "Unable to remove temporary file."; return Diff; Index: llvm/lib/Passes/StandardInstrumentations.cpp =================================================================== --- llvm/lib/Passes/StandardInstrumentations.cpp +++ llvm/lib/Passes/StandardInstrumentations.cpp @@ -501,7 +501,7 @@ static SmallVector FD{-1}; SmallVector SR{S}; static SmallVector FileName{""}; - if (auto Err = prepareTempFiles(FD, SR, FileName)) { + if (prepareTempFiles(FD, SR, FileName)) { dbgs() << "Unable to create temporary file."; return; } @@ -518,7 +518,7 @@ return; } - if (auto Err = cleanUpTempFiles(FileName)) + if (cleanUpTempFiles(FileName)) dbgs() << "Unable to remove temporary file."; } Index: llvm/lib/Support/VirtualFileSystem.cpp =================================================================== --- llvm/lib/Support/VirtualFileSystem.cpp +++ llvm/lib/Support/VirtualFileSystem.cpp @@ -1337,7 +1337,7 @@ SmallString<256> Path; Path_.toVector(Path); - if (std::error_code EC = makeCanonical(Path)) + if (makeCanonical(Path)) return {}; return ExternalFS->isLocal(Path, Result); Index: llvm/lib/Transforms/Vectorize/LoopVectorize.cpp =================================================================== --- llvm/lib/Transforms/Vectorize/LoopVectorize.cpp +++ llvm/lib/Transforms/Vectorize/LoopVectorize.cpp @@ -9178,7 +9178,7 @@ VecOp = FMulRecipe; } else { if (RecurrenceDescriptor::isMinMaxRecurrenceKind(Kind)) { - if (auto *Cmp = dyn_cast(CurrentLink)) { + if (isa(CurrentLink)) { assert(isa(CurrentLinkI) && "need to have the compare of the select"); continue; Index: llvm/tools/llvm-profgen/ProfiledBinary.cpp =================================================================== --- llvm/tools/llvm-profgen/ProfiledBinary.cpp +++ llvm/tools/llvm-profgen/ProfiledBinary.cpp @@ -812,7 +812,7 @@ // Handles DWO sections that can either be in .o, .dwo or .dwp files. for (const auto &CompilationUnit : DebugContext->compile_units()) { DWARFUnit *const DwarfUnit = CompilationUnit.get(); - if (std::optional DWOId = DwarfUnit->getDWOId()) { + if (DwarfUnit->getDWOId()) { DWARFUnit *DWOCU = DwarfUnit->getNonSkeletonUnitDIE(false).getDwarfUnit(); if (!DWOCU->isDWOUnit()) { std::string DWOName = dwarf::toString(