Skip to content

Commit 92023b1

Browse files
committed
Reland "[Clang][SemaCXX] Add unused warning for variables declared in condition expressions"
This patch marks the declarations with initializations in condition expressions such as if (int var = init) as unused and unreferenced so that -Wunused can warn on them. Fixes llvm#61681 Reviewed By: cor3ntin Differential Revision: https://reviews.llvm.org/D152495
1 parent 01b88dd commit 92023b1

File tree

5 files changed

+122
-3
lines changed

5 files changed

+122
-3
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ Improvements to Clang's diagnostics
156156
(`#64871: <https://github.com/llvm/llvm-project/issues/64871>`_).
157157
Also clang no longer emits false positive warnings about the output length of
158158
``%g`` format specifier.
159+
- Clang now warns on unused variables declared and initialized in condition
160+
expressions.
161+
(`#61681: <https://github.com/llvm/llvm-project/issues/61681>`_)
159162

160163
Bug Fixes in This Version
161164
-------------------------

clang/lib/Sema/SemaDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1995,7 +1995,7 @@ static bool ShouldDiagnoseUnusedDecl(const LangOptions &LangOpts,
19951995
return false;
19961996
} else if (!D->getDeclName()) {
19971997
return false;
1998-
} else if (D->isReferenced() || D->isUsed()) {
1998+
} else if (D->isReferenced() || (!isa<VarDecl>(D) && D->isUsed())) {
19991999
return false;
20002000
}
20012001

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4013,6 +4013,10 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
40134013
ConditionVar, ConditionVar->getType().getNonReferenceType(), VK_LValue,
40144014
ConditionVar->getLocation());
40154015

4016+
// Ensure that `-Wunused-variable` will be emitted for condition variables
4017+
// that are not referenced later. e.g.: if (int var = init());
4018+
ConditionVar->setReferenced(/*R=*/false);
4019+
40164020
switch (CK) {
40174021
case ConditionKind::Boolean:
40184022
return CheckBooleanCondition(StmtLoc, Condition.get());

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5353,7 +5353,7 @@ void Sema::BuildVariableInstantiation(
53535353
// will have been deferred.
53545354
if (!NewVar->isInvalidDecl() &&
53555355
NewVar->getDeclContext()->isFunctionOrMethod() &&
5356-
OldVar->getType()->isDependentType())
5356+
OldVar->getType()->isDependentType() && !OldVar->isImplicit())
53575357
DiagnoseUnusedDecl(NewVar);
53585358
}
53595359

clang/test/SemaCXX/warn-unused-variables.cpp

Lines changed: 113 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify %s
2-
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++1y-extensions -verify -std=c++11 %s
2+
// RUN: %clang_cc1 -fsyntax-only -Wunused-variable -Wunused-label -Wno-c++14-extensions -Wno-c++17-extensions -verify -std=c++11 %s
33
template<typename T> void f() {
44
T t;
55
t = 17;
@@ -294,3 +294,115 @@ void RAIIWrapperTest() {
294294
}
295295

296296
} // namespace gh54489
297+
298+
namespace inside_condition {
299+
void ifs() {
300+
if (int hoge = 0) // expected-warning {{unused variable 'hoge'}}
301+
return;
302+
if (const int const_hoge = 0) // expected-warning {{unused variable 'const_hoge'}}
303+
return;
304+
else if (int fuga = 0)
305+
(void)fuga;
306+
else if (int used = 1; int catched = used) // expected-warning {{unused variable 'catched'}}
307+
return;
308+
else if (int refed = 1; int used = refed)
309+
(void)used;
310+
else if (int unused1 = 2; int unused2 = 3) // expected-warning {{unused variable 'unused1'}} \
311+
// expected-warning {{unused variable 'unused2'}}
312+
return;
313+
else if (int unused = 4; int used = 5) // expected-warning {{unused variable 'unused'}}
314+
(void)used;
315+
else if (int used = 6; int unused = 7) // expected-warning {{unused variable 'unused'}}
316+
(void)used;
317+
else if (int used1 = 8; int used2 = 9)
318+
(void)(used1 + used2);
319+
else if (auto [a, b] = (int[2]){ 1, 2 }; 1) // expected-warning {{unused variable '[a, b]'}}
320+
return;
321+
else if (auto [a, b] = (int[2]){ 1, 2 }; a)
322+
return;
323+
}
324+
325+
void fors() {
326+
for (int i = 0;int unused = 0;); // expected-warning {{unused variable 'i'}} \
327+
// expected-warning {{unused variable 'unused'}}
328+
for (int i = 0;int used = 0;) // expected-warning {{unused variable 'i'}}
329+
(void)used;
330+
while(int var = 1) // expected-warning {{unused variable 'var'}}
331+
return;
332+
}
333+
334+
void whiles() {
335+
while(int unused = 1) // expected-warning {{unused variable 'unused'}}
336+
return;
337+
while(int used = 1)
338+
(void)used;
339+
}
340+
341+
342+
void switches() {
343+
switch(int unused = 1) { // expected-warning {{unused variable 'unused'}}
344+
case 1: return;
345+
}
346+
switch(constexpr int used = 3; int unused = 4) { // expected-warning {{unused variable 'unused'}}
347+
case used: return;
348+
}
349+
switch(int used = 3; int unused = 4) { // expected-warning {{unused variable 'unused'}}
350+
case 3: (void)used;
351+
}
352+
switch(constexpr int used1 = 0; constexpr int used2 = 6) {
353+
case (used1+used2): return;
354+
}
355+
switch(auto [a, b] = (int[2]){ 1, 2 }; 1) { // expected-warning {{unused variable '[a, b]'}}
356+
case 1: return;
357+
}
358+
switch(auto [a, b] = (int[2]){ 1, 2 }; b) {
359+
case 1: return;
360+
}
361+
switch(auto [a, b] = (int[2]){ 1, 2 }; 1) {
362+
case 1: (void)a;
363+
}
364+
}
365+
template <typename T>
366+
struct Vector {
367+
void doIt() {
368+
for (auto& e : elements){} // expected-warning {{unused variable 'e'}}
369+
}
370+
T elements[10];
371+
};
372+
void ranged_for() {
373+
Vector<int> vector;
374+
vector.doIt(); // expected-note {{here}}
375+
}
376+
377+
378+
struct RAII {
379+
int &x;
380+
RAII(int &ref) : x(ref) {}
381+
~RAII() { x = 0;}
382+
operator int() const { return 1; }
383+
};
384+
void aggregate() {
385+
int x = 10;
386+
int y = 10;
387+
if (RAII var = x) {}
388+
for(RAII var = x; RAII var2 = y;) {}
389+
while (RAII var = x) {}
390+
switch (RAII var = x) {}
391+
}
392+
393+
struct TrivialDtor{
394+
int &x;
395+
TrivialDtor(int &ref) : x(ref) { ref = 32; }
396+
operator int() const { return 1; }
397+
};
398+
void trivial_dtor() {
399+
int x = 10;
400+
int y = 10;
401+
if (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}}
402+
for(TrivialDtor var = x; TrivialDtor var2 = y;) {} // expected-warning {{unused variable 'var'}} \
403+
// expected-warning {{unused variable 'var2'}}
404+
while (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}}
405+
switch (TrivialDtor var = x) {} // expected-warning {{unused variable 'var'}}
406+
}
407+
408+
} // namespace inside_condition

0 commit comments

Comments
 (0)