Improve our handling of the -Wunused-variable warning in templates. In

particular, don't complain about unused variables that have dependent
type until instantiation time, so that we can look at the type of the
variable. Moreover, only complain about unused variables that have
neither a user-declared constructor nor a non-trivial destructor.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103362 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Douglas Gregor 2010-05-08 23:05:03 +00:00
Родитель c6dfe194f6
Коммит 5764f613e6
4 изменённых файлов: 51 добавлений и 17 удалений

Просмотреть файл

@ -1761,7 +1761,8 @@ public:
/// DiagnoseUnusedExprResult - If the statement passed in is an expression /// DiagnoseUnusedExprResult - If the statement passed in is an expression
/// whose result is unused, warn. /// whose result is unused, warn.
void DiagnoseUnusedExprResult(const Stmt *S); void DiagnoseUnusedExprResult(const Stmt *S);
void DiagnoseUnusedDecl(const NamedDecl *ND);
ParsingDeclStackState PushParsingDeclaration(); ParsingDeclStackState PushParsingDeclaration();
void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D); void PopParsingDeclaration(ParsingDeclStackState S, DeclPtrTy D);
void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc); void EmitDeprecationWarning(NamedDecl *D, SourceLocation Loc);

Просмотреть файл

@ -544,9 +544,9 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false; return false;
} }
// If we failed to complete the type for some reason, don't // If we failed to complete the type for some reason, or if the type is
// diagnose the variable. // dependent, don't diagnose the variable.
if (Ty->isIncompleteType()) if (Ty->isIncompleteType() || Ty->isDependentType())
return false; return false;
if (const TagType *TT = Ty->getAs<TagType>()) { if (const TagType *TT = Ty->getAs<TagType>()) {
@ -555,9 +555,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return false; return false;
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Tag)) {
if (!RD->hasTrivialConstructor()) // FIXME: Checking for the presence of a user-declared constructor
return false; // isn't completely accurate; we'd prefer to check that the initializer
if (!RD->hasTrivialDestructor()) // has no side effects.
if (RD->hasUserDeclaredConstructor() || !RD->hasTrivialDestructor())
return false; return false;
} }
} }
@ -568,6 +569,18 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
return true; return true;
} }
void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
if (!ShouldDiagnoseUnusedDecl(D))
return;
if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
Diag(D->getLocation(), diag::warn_unused_exception_param)
<< D->getDeclName();
else
Diag(D->getLocation(), diag::warn_unused_variable)
<< D->getDeclName();
}
void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (S->decl_empty()) return; if (S->decl_empty()) return;
assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) && assert((S->getFlags() & (Scope::DeclScope | Scope::TemplateParamScope)) &&
@ -584,15 +597,9 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (!D->getDeclName()) continue; if (!D->getDeclName()) continue;
// Diagnose unused variables in this scope. // Diagnose unused variables in this scope.
if (ShouldDiagnoseUnusedDecl(D) && if (S->getNumErrorsAtStart() == getDiagnostics().getNumErrors())
S->getNumErrorsAtStart() == getDiagnostics().getNumErrors()) { DiagnoseUnusedDecl(D);
if (isa<VarDecl>(D) && cast<VarDecl>(D)->isExceptionVariable())
Diag(D->getLocation(), diag::warn_unused_exception_param)
<< D->getDeclName();
else
Diag(D->getLocation(), diag::warn_unused_variable)
<< D->getDeclName();
}
// Remove this name from our lexical scope. // Remove this name from our lexical scope.
IdResolver.RemoveDecl(D); IdResolver.RemoveDecl(D);
} }

Просмотреть файл

@ -351,7 +351,8 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Var->setLexicalDeclContext(D->getLexicalDeclContext()); Var->setLexicalDeclContext(D->getLexicalDeclContext());
Var->setAccess(D->getAccess()); Var->setAccess(D->getAccess());
Var->setUsed(D->isUsed());
// FIXME: In theory, we could have a previous declaration for variables that // FIXME: In theory, we could have a previous declaration for variables that
// are not static data members. // are not static data members.
bool Redeclaration = false; bool Redeclaration = false;
@ -419,6 +420,10 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
} else if (!Var->isStaticDataMember() || Var->isOutOfLine()) } else if (!Var->isStaticDataMember() || Var->isOutOfLine())
SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false); SemaRef.ActOnUninitializedDecl(Sema::DeclPtrTy::make(Var), false);
// Diagnose unused local variables.
if (!Var->isInvalidDecl() && Owner->isFunctionOrMethod() && !Var->isUsed())
SemaRef.DiagnoseUnusedDecl(Var);
return Var; return Var;
} }

Просмотреть файл

@ -0,0 +1,21 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused -verify %s
struct X0 {
~X0();
};
struct X1 { };
template<typename T>
void f() {
X0 x0;
X1 x1; // expected-warning{{unused variable 'x1'}}
}
template<typename T, typename U>
void g() {
T t;
U u; // expected-warning{{unused variable 'u'}}
}
template void g<X0, X1>(); // expected-note{{in instantiation of}}