Keep track of when declarations are "used" according to C and
C++. This logic is required to trigger implicit instantiation of
function templates and member functions of class templates, which will
be implemented separately.
This commit includes support for -Wunused-parameter, printing warnings
for named parameters that are not used within a function/Objective-C
method/block. Fixes <rdar://problem/6505209>.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@73797 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp
index 60d8e5f..e756b41 100644
--- a/lib/Sema/Sema.cpp
+++ b/lib/Sema/Sema.cpp
@@ -182,7 +182,7 @@
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
ExternalSource(0), CurContext(0), PreDeclaratorDC(0),
CurBlock(0), PackContext(0), IdResolver(pp.getLangOptions()),
- GlobalNewDeleteDeclared(false),
+ GlobalNewDeleteDeclared(false), InUnevaluatedOperand(false),
CompleteTranslationUnit(CompleteTranslationUnit),
NumSFINAEErrors(0), CurrentInstantiationScope(0) {
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 23bab23..230bcff 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -18,7 +18,9 @@
#include "IdentifierResolver.h"
#include "CXXFieldCollector.h"
#include "SemaOverload.h"
+#include "clang/AST/Attr.h"
#include "clang/AST/DeclBase.h"
+#include "clang/AST/Decl.h"
#include "clang/AST/DeclObjC.h"
#include "clang/AST/DeclTemplate.h"
#include "clang/Parse/Action.h"
@@ -245,6 +247,12 @@
/// have been declared.
bool GlobalNewDeleteDeclared;
+ /// A flag that indicates when we are processing an unevaluated operand
+ /// (C++0x [expr]). C99 has the same notion of declarations being
+ /// "used" and C++03 has the notion of "potentially evaluated", but we
+ /// adopt the C++0x terminology since it is most precise.
+ bool InUnevaluatedOperand;
+
/// \brief Whether the code handled by Sema should be considered a
/// complete translation unit or not.
///
@@ -454,6 +462,19 @@
virtual DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body);
DeclPtrTy ActOnFinishFunctionBody(DeclPtrTy Decl, StmtArg Body,
bool IsInstantiation);
+
+ /// \brief Diagnose any unused parameters in the given sequence of
+ /// ParmVarDecl pointers.
+ template<typename InputIterator>
+ void DiagnoseUnusedParameters(InputIterator Param, InputIterator ParamEnd) {
+ for (; Param != ParamEnd; ++Param) {
+ if (!(*Param)->isUsed() && (*Param)->getDeclName() &&
+ !(*Param)->template hasAttr<UnusedAttr>(Context))
+ Diag((*Param)->getLocation(), diag::warn_unused_parameter)
+ << (*Param)->getDeclName();
+ }
+ }
+
void DiagnoseInvalidJumps(Stmt *Body);
virtual DeclPtrTy ActOnFileScopeAsmDecl(SourceLocation Loc, ExprArg expr);
@@ -694,6 +715,7 @@
bool isBetterOverloadCandidate(const OverloadCandidate& Cand1,
const OverloadCandidate& Cand2);
OverloadingResult BestViableFunction(OverloadCandidateSet& CandidateSet,
+ SourceLocation Loc,
OverloadCandidateSet::iterator& Best);
void PrintOverloadCandidates(OverloadCandidateSet& CandidateSet,
bool OnlyViable);
@@ -1312,6 +1334,14 @@
void DiagnoseSentinelCalls(NamedDecl *D, SourceLocation Loc,
Expr **Args, unsigned NumArgs);
+ virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) {
+ bool Result = InUnevaluatedOperand;
+ InUnevaluatedOperand = UnevaluatedOperand;
+ return Result;
+ }
+
+ void MarkDeclarationReferenced(SourceLocation Loc, Decl *D);
+
// Primary Expressions.
virtual SourceRange getExprRange(ExprTy *E) const;
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp
index c4d1fe9..2dd02af 100644
--- a/lib/Sema/SemaDecl.cpp
+++ b/lib/Sema/SemaDecl.cpp
@@ -3094,10 +3094,23 @@
Stmt *Body = BodyArg.takeAs<Stmt>();
if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(dcl)) {
FD->setBody(Body);
+
+ if (!FD->isInvalidDecl())
+ DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
+
+ // C++ [basic.def.odr]p2:
+ // [...] A virtual member function is used if it is not pure. [...]
+ if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD))
+ if (Method->isVirtual() && !Method->isPure())
+ MarkDeclarationReferenced(Method->getLocation(), Method);
+
assert(FD == getCurFunctionDecl() && "Function parsing confused");
} else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(dcl)) {
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
+
+ if (!MD->isInvalidDecl())
+ DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
} else {
Body->Destroy(Context);
return DeclPtrTy();
diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp
index fd1cc04..8c547cd 100644
--- a/lib/Sema/SemaDeclCXX.cpp
+++ b/lib/Sema/SemaDeclCXX.cpp
@@ -2031,7 +2031,7 @@
// constructors, we'll need to make them appear here.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, Loc, Best)) {
case OR_Success:
// We found a constructor. Return it.
return cast<CXXConstructorDecl>(Best->Function);
@@ -2263,7 +2263,7 @@
}
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, Init->getLocStart(), Best)) {
case OR_Success:
// This is a direct binding.
BindsDirectly = true;
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp
index de56819..692502b 100644
--- a/lib/Sema/SemaExpr.cpp
+++ b/lib/Sema/SemaExpr.cpp
@@ -627,6 +627,7 @@
Sema::BuildDeclRefExpr(NamedDecl *D, QualType Ty, SourceLocation Loc,
bool TypeDependent, bool ValueDependent,
const CXXScopeSpec *SS) {
+ MarkDeclarationReferenced(Loc, D);
if (SS && !SS->isEmpty()) {
return new (Context) QualifiedDeclRefExpr(D, Ty, Loc, TypeDependent,
ValueDependent, SS->getRange(),
@@ -721,6 +722,7 @@
// BaseObject is an anonymous struct/union variable (and is,
// therefore, not part of another non-anonymous record).
if (BaseObjectExpr) BaseObjectExpr->Destroy(Context);
+ MarkDeclarationReferenced(Loc, BaseObject);
BaseObjectExpr = new (Context) DeclRefExpr(BaseObject,BaseObject->getType(),
SourceLocation());
ExtraQuals
@@ -777,6 +779,7 @@
= MemberType.getCVRQualifiers() | ExtraQuals;
MemberType = MemberType.getQualifiedType(combinedQualifiers);
}
+ MarkDeclarationReferenced(Loc, *FI);
Result = new (Context) MemberExpr(Result, BaseObjectIsPointer, *FI,
OpLoc, MemberType);
BaseObjectIsPointer = false;
@@ -876,6 +879,7 @@
// turn this into Self->ivar, just return a BareIVarExpr or something.
IdentifierInfo &II = Context.Idents.get("self");
OwningExprResult SelfExpr = ActOnIdentifierExpr(S, Loc, II, false);
+ MarkDeclarationReferenced(Loc, IV);
return Owned(new (Context)
ObjCIvarRefExpr(IV, IV->getType(), Loc,
SelfExpr.takeAs<Expr>(), true, true));
@@ -1025,6 +1029,7 @@
// Build the implicit member access expression.
Expr *This = new (Context) CXXThisExpr(SourceLocation(),
MD->getThisType(Context));
+ MarkDeclarationReferenced(Loc, D);
return Owned(new (Context) MemberExpr(This, true, D,
Loc, MemberType));
}
@@ -1125,6 +1130,7 @@
// as they do not get snapshotted.
//
if (CurBlock && ShouldSnapshotBlockValueReference(CurBlock, VD)) {
+ MarkDeclarationReferenced(Loc, VD);
QualType ExprTy = VD->getType().getNonReferenceType();
// The BlocksAttr indicates the variable is bound by-reference.
if (VD->getAttr<BlocksAttr>(Context))
@@ -1579,7 +1585,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
case OR_Success: {
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
@@ -1689,7 +1695,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, LLoc, Best)) {
case OR_Success: {
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
@@ -5258,7 +5264,7 @@
BSI->isVariadic, 0);
// FIXME: Check that return/parameter types are complete/non-abstract
-
+ DiagnoseUnusedParameters(BSI->Params.begin(), BSI->Params.end());
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
@@ -5425,3 +5431,49 @@
*Result = EvalResult.Val.getInt();
return false;
}
+
+
+/// \brief Note that the given declaration was referenced in the source code.
+///
+/// This routine should be invoke whenever a given declaration is referenced
+/// in the source code, and where that reference occurred. If this declaration
+/// reference means that the the declaration is used (C++ [basic.def.odr]p2,
+/// C99 6.9p3), then the declaration will be marked as used.
+///
+/// \param Loc the location where the declaration was referenced.
+///
+/// \param D the declaration that has been referenced by the source code.
+void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
+ assert(D && "No declaration?");
+
+ // Mark a parameter declaration "used", regardless of whether we're in a
+ // template or not.
+ if (isa<ParmVarDecl>(D))
+ D->setUsed(true);
+
+ // Do not mark anything as "used" within a dependent context; wait for
+ // an instantiation.
+ if (CurContext->isDependentContext())
+ return;
+
+ // If we are in an unevaluated operand, don't mark any definitions as used.
+ if (InUnevaluatedOperand)
+ return;
+
+ // Note that this declaration has been used.
+ if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {
+ // FIXME: implicit template instantiation
+ // FIXME: keep track of references to static functions
+ (void)Function;
+ Function->setUsed(true);
+ return;
+ }
+
+ if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
+ (void)Var;
+ // FIXME: implicit template instantiation
+ // FIXME: keep track of references to static data?
+ D->setUsed(true);
+ }
+}
+
diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp
index 7353efb..bec595c 100644
--- a/lib/Sema/SemaExprCXX.cpp
+++ b/lib/Sema/SemaExprCXX.cpp
@@ -546,7 +546,7 @@
// Do the resolution.
OverloadCandidateSet::iterator Best;
- switch(BestViableFunction(Candidates, Best)) {
+ switch(BestViableFunction(Candidates, StartLoc, Best)) {
case OR_Success: {
// Got one!
FunctionDecl *FnDecl = Best->Function;
@@ -1175,7 +1175,7 @@
Self.AddBuiltinOperatorCandidates(OO_Conditional, Args, 2, CandidateSet);
OverloadCandidateSet::iterator Best;
- switch (Self.BestViableFunction(CandidateSet, Best)) {
+ switch (Self.BestViableFunction(CandidateSet, Loc, Best)) {
case Sema::OR_Success:
// We found a match. Perform the conversions on the arguments and move on.
if (Self.PerformImplicitConversion(LHS, Best->BuiltinTypes.ParamTypes[0],
diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp
index e81985b..11cd510 100644
--- a/lib/Sema/SemaOverload.cpp
+++ b/lib/Sema/SemaOverload.cpp
@@ -1379,7 +1379,7 @@
}
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, From->getLocStart(), Best)) {
case OR_Success:
// Record the standard conversion we used and the conversion function.
if (CXXConstructorDecl *Constructor
@@ -3445,14 +3445,21 @@
return false;
}
-/// BestViableFunction - Computes the best viable function (C++ 13.3.3)
-/// within an overload candidate set. If overloading is successful,
-/// the result will be OR_Success and Best will be set to point to the
-/// best viable function within the candidate set. Otherwise, one of
-/// several kinds of errors will be returned; see
-/// Sema::OverloadingResult.
+/// \brief Computes the best viable function (C++ 13.3.3)
+/// within an overload candidate set.
+///
+/// \param CandidateSet the set of candidate functions.
+///
+/// \param Loc the location of the function name (or operator symbol) for
+/// which overload resolution occurs.
+///
+/// \param Best f overload resolution was successful or found a deleted
+/// function, Best points to the candidate function found.
+///
+/// \returns The result of overload resolution.
Sema::OverloadingResult
Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
+ SourceLocation Loc,
OverloadCandidateSet::iterator& Best)
{
// Find the best viable function.
@@ -3487,9 +3494,14 @@
Best->Function->getAttr<UnavailableAttr>(Context)))
return OR_Deleted;
- // If Best refers to a function that is either deleted (C++0x) or
- // unavailable (Clang extension) report an error.
-
+ // C++ [basic.def.odr]p2:
+ // An overloaded function is used if it is selected by overload resolution
+ // when referred to from a potentially-evaluated expression. [Note: this
+ // covers calls to named functions (5.2.2), operator overloading
+ // (clause 13), user-defined conversions (12.3.2), allocation function for
+ // placement new (5.3.4), as well as non-default initialization (8.5).
+ if (Best->Function)
+ MarkDeclarationReferenced(Loc, Best->Function);
return OR_Success;
}
@@ -3709,7 +3721,7 @@
CandidateSet);
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
case OR_Success:
return Best->Function;
@@ -3815,7 +3827,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
case OR_Success: {
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
@@ -3968,7 +3980,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
case OR_Success: {
// We found a built-in operator or an overloaded operator.
FunctionDecl *FnDecl = Best->Function;
@@ -4094,7 +4106,7 @@
}
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, MemExpr->getLocStart(), Best)) {
case OR_Success:
Method = cast<CXXMethodDecl>(Best->Function);
break;
@@ -4219,7 +4231,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, Object->getLocStart(), Best)) {
case OR_Success:
// Overload resolution succeeded; we'll build the appropriate call
// below.
@@ -4388,7 +4400,7 @@
// Perform overload resolution.
OverloadCandidateSet::iterator Best;
- switch (BestViableFunction(CandidateSet, Best)) {
+ switch (BestViableFunction(CandidateSet, OpLoc, Best)) {
case OR_Success:
// Overload resolution succeeded; we'll build the call below.
break;