forked from OSchip/llvm-project
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>. llvm-svn: 73797
This commit is contained in:
parent
724f825f96
commit
c9c02ed8f4
|
@ -156,6 +156,10 @@ private:
|
|||
/// the implementation rather than explicitly written by the user.
|
||||
bool Implicit : 1;
|
||||
|
||||
/// \brief Whether this declaration was "used", meaning that a definition is
|
||||
/// required.
|
||||
bool Used : 1;
|
||||
|
||||
/// IdentifierNamespace - This specifies what IDNS_* namespace this lives in.
|
||||
unsigned IdentifierNamespace : 8;
|
||||
|
||||
|
@ -174,7 +178,7 @@ protected:
|
|||
Decl(Kind DK, DeclContext *DC, SourceLocation L)
|
||||
: NextDeclInContext(0), DeclCtx(DC),
|
||||
Loc(L), DeclKind(DK), InvalidDecl(0),
|
||||
HasAttrs(false), Implicit(false),
|
||||
HasAttrs(false), Implicit(false), Used(false),
|
||||
IdentifierNamespace(getIdentifierNamespaceForKind(DK)), Access(AS_none) {
|
||||
if (Decl::CollectingStats()) addDeclKind(DK);
|
||||
}
|
||||
|
@ -241,6 +245,11 @@ public:
|
|||
bool isImplicit() const { return Implicit; }
|
||||
void setImplicit(bool I = true) { Implicit = I; }
|
||||
|
||||
/// \brief Whether this declaration was used, meaning that a definition
|
||||
/// is required.
|
||||
bool isUsed() const { return Used; }
|
||||
void setUsed(bool U = true) { Used = U; }
|
||||
|
||||
unsigned getIdentifierNamespace() const {
|
||||
return IdentifierNamespace;
|
||||
}
|
||||
|
|
|
@ -116,7 +116,9 @@ def Format2 : DiagGroup<"format=2",
|
|||
[FormatNonLiteral, FormatSecurity, FormatY2K]>;
|
||||
|
||||
|
||||
def Extra : DiagGroup<"extra">;
|
||||
def Extra : DiagGroup<"extra", [
|
||||
UnusedParameter
|
||||
]>;
|
||||
|
||||
def Most : DiagGroup<"most", [
|
||||
Comment,
|
||||
|
|
|
@ -72,6 +72,8 @@ def ext_anon_param_requires_type_specifier : Extension<
|
|||
def err_bad_variable_name : Error<
|
||||
"'%0' cannot be the name of a variable or data member">;
|
||||
def err_parameter_name_omitted : Error<"parameter name omitted">;
|
||||
def warn_unused_parameter : Warning<"unused parameter %0">,
|
||||
InGroup<UnusedParameter>, DefaultIgnore;
|
||||
def warn_decl_in_param_list : Warning<
|
||||
"declaration of %0 will not be visible outside of this function">;
|
||||
|
||||
|
|
|
@ -637,6 +637,18 @@ public:
|
|||
// Expression Parsing Callbacks.
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
/// \brief Notifies the action when the parser is processing an unevaluated
|
||||
/// operand.
|
||||
///
|
||||
/// \param UnevaluatedOperand true to indicate that the parser is processing
|
||||
/// an unevaluated operand, or false otherwise.
|
||||
///
|
||||
/// \returns whether the the action module was previously in an unevaluated
|
||||
/// operand.
|
||||
virtual bool setUnevaluatedOperand(bool UnevaluatedOperand) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Primary Expressions.
|
||||
|
||||
/// \brief Retrieve the source range that corresponds to the given
|
||||
|
|
|
@ -105,6 +105,24 @@ class Parser {
|
|||
}
|
||||
};
|
||||
|
||||
/// \brief RAII object that enters an unevaluated operand.
|
||||
class EnterUnevaluatedOperand {
|
||||
/// \brief The action object.
|
||||
Action &Actions;
|
||||
|
||||
/// \brief Whether we were previously within an unevaluated operand.
|
||||
bool PreviouslyInUnevaluatedOperand;
|
||||
|
||||
public:
|
||||
explicit EnterUnevaluatedOperand(Action &Actions) : Actions(Actions) {
|
||||
PreviouslyInUnevaluatedOperand = Actions.setUnevaluatedOperand(true);
|
||||
}
|
||||
|
||||
~EnterUnevaluatedOperand() {
|
||||
Actions.setUnevaluatedOperand(PreviouslyInUnevaluatedOperand);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
Parser(Preprocessor &PP, Action &Actions);
|
||||
~Parser();
|
||||
|
|
|
@ -82,6 +82,7 @@ void PCHDeclReader::VisitDecl(Decl *D) {
|
|||
if (Record[Idx++])
|
||||
D->addAttr(*Reader.getContext(), Reader.ReadAttributes());
|
||||
D->setImplicit(Record[Idx++]);
|
||||
D->setUsed(Record[Idx++]);
|
||||
D->setAccess((AccessSpecifier)Record[Idx++]);
|
||||
}
|
||||
|
||||
|
|
|
@ -82,6 +82,7 @@ void PCHDeclWriter::VisitDecl(Decl *D) {
|
|||
Record.push_back(D->isInvalidDecl());
|
||||
Record.push_back(D->hasAttrs());
|
||||
Record.push_back(D->isImplicit());
|
||||
Record.push_back(D->isUsed());
|
||||
Record.push_back(D->getAccess());
|
||||
}
|
||||
|
||||
|
@ -360,6 +361,7 @@ void PCHDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
|
|||
// know are true of all PARM_VAR_DECLs.
|
||||
if (!D->hasAttrs() &&
|
||||
!D->isImplicit() &&
|
||||
!D->isUsed() &&
|
||||
D->getAccess() == AS_none &&
|
||||
D->getStorageClass() == 0 &&
|
||||
!D->hasCXXDirectInitializer() && // Can params have this ever?
|
||||
|
@ -434,6 +436,7 @@ void PCHWriter::WriteDeclsBlockAbbrevs() {
|
|||
Abv->Add(BitCodeAbbrevOp(0)); // isInvalidDecl (!?)
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
|
||||
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
|
||||
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
|
||||
|
||||
// NamedDecl
|
||||
|
|
|
@ -2699,8 +2699,12 @@ void Parser::ParseBracketDeclarator(Declarator &D) {
|
|||
// things like '=' and '*='. Sema rejects these in C89 mode because they
|
||||
// are not i-c-e's, so we don't need to distinguish between the two here.
|
||||
|
||||
// Parse the assignment-expression now.
|
||||
NumElements = ParseAssignmentExpression();
|
||||
// Parse the constant-expression or assignment-expression now (depending
|
||||
// on dialect).
|
||||
if (getLang().CPlusPlus)
|
||||
NumElements = ParseConstantExpression();
|
||||
else
|
||||
NumElements = ParseAssignmentExpression();
|
||||
}
|
||||
|
||||
// If there was an error parsing the assignment-expression, recover.
|
||||
|
|
|
@ -279,7 +279,7 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){
|
|||
}
|
||||
|
||||
SourceLocation LParenLoc = ConsumeParen();
|
||||
|
||||
|
||||
OwningExprResult AssertExpr(ParseConstantExpression());
|
||||
if (AssertExpr.isInvalid()) {
|
||||
SkipUntil(tok::semi);
|
||||
|
|
|
@ -276,6 +276,11 @@ Parser::ParseAssignmentExprWithObjCMessageExprStart(SourceLocation LBracLoc,
|
|||
|
||||
|
||||
Parser::OwningExprResult Parser::ParseConstantExpression() {
|
||||
// C++ [basic.def.odr]p2:
|
||||
// An expression is potentially evaluated unless it appears where an
|
||||
// integral constant expression is required (see 5.19) [...].
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
|
||||
OwningExprResult LHS(ParseCastExpression(false));
|
||||
if (LHS.isInvalid()) return move(LHS);
|
||||
|
||||
|
@ -971,8 +976,15 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
|
|||
Diag(Tok,diag::err_expected_lparen_after_id) << OpTok.getIdentifierInfo();
|
||||
return ExprError();
|
||||
}
|
||||
|
||||
// C++0x [expr.sizeof]p1:
|
||||
// [...] The operand is either an expression, which is an unevaluated
|
||||
// operand (Clause 5) [...]
|
||||
//
|
||||
// The GNU typeof and alignof extensions also behave as unevaluated
|
||||
// operands.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
Operand = ParseCastExpression(true/*isUnaryExpression*/);
|
||||
|
||||
} else {
|
||||
// If it starts with a '(', we know that it is either a parenthesized
|
||||
// type-name, or it is a unary-expression that starts with a compound
|
||||
|
@ -980,6 +992,14 @@ Parser::ParseExprAfterTypeofSizeofAlignof(const Token &OpTok,
|
|||
// expression.
|
||||
ParenParseOption ExprType = CastExpr;
|
||||
SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
|
||||
|
||||
// C++0x [expr.sizeof]p1:
|
||||
// [...] The operand is either an expression, which is an unevaluated
|
||||
// operand (Clause 5) [...]
|
||||
//
|
||||
// The GNU typeof and alignof extensions also behave as unevaluated
|
||||
// operands.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
Operand = ParseParenExpression(ExprType, true/*stopIfCastExpr*/,
|
||||
CastTy, RParenLoc);
|
||||
CastRange = SourceRange(LParenLoc, RParenLoc);
|
||||
|
|
|
@ -377,6 +377,17 @@ Parser::OwningExprResult Parser::ParseCXXTypeid() {
|
|||
Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
|
||||
Ty.get(), RParenLoc);
|
||||
} else {
|
||||
// C++0x [expr.typeid]p3:
|
||||
// When typeid is applied to an expression other than an lvalue of a
|
||||
// polymorphic class type [...] The expression is an unevaluated
|
||||
// operand (Clause 5).
|
||||
//
|
||||
// Note that we can't tell whether the expression is an lvalue of a
|
||||
// polymorphic class type until after we've parsed the expression, so
|
||||
// we treat the expression as an unevaluated operand and let semantic
|
||||
// analysis cope with case where the expression is not an unevaluated
|
||||
// operand.
|
||||
EnterUnevaluatedOperand Unevaluated(Actions);
|
||||
Result = ParseExpression();
|
||||
|
||||
// Match the ')'.
|
||||
|
|
|
@ -182,7 +182,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
|
|||
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) {
|
||||
|
||||
|
|
|
@ -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 @@ public:
|
|||
/// 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 @@ public:
|
|||
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 @@ public:
|
|||
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 @@ public:
|
|||
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;
|
||||
|
||||
|
|
|
@ -3094,10 +3094,23 @@ Sema::DeclPtrTy Sema::ActOnFinishFunctionBody(DeclPtrTy D, StmtArg BodyArg,
|
|||
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();
|
||||
|
|
|
@ -2031,7 +2031,7 @@ Sema::PerformInitializationByConstructor(QualType ClassType,
|
|||
// 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 @@ Sema::CheckReferenceInit(Expr *&Init, QualType DeclType,
|
|||
}
|
||||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (BestViableFunction(CandidateSet, Best)) {
|
||||
switch (BestViableFunction(CandidateSet, Init->getLocStart(), Best)) {
|
||||
case OR_Success:
|
||||
// This is a direct binding.
|
||||
BindsDirectly = true;
|
||||
|
|
|
@ -627,6 +627,7 @@ DeclRefExpr *
|
|||
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 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|||
// 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 @@ Sema::BuildAnonymousStructUnionMemberReference(SourceLocation Loc,
|
|||
= 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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
// 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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
// 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 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc,
|
|||
// 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 @@ Sema::ActOnPostfixUnaryOp(Scope *S, SourceLocation OpLoc,
|
|||
|
||||
// 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 @@ Sema::ActOnArraySubscriptExpr(Scope *S, ExprArg Base, SourceLocation LLoc,
|
|||
|
||||
// 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 @@ Sema::OwningExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
|
|||
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 @@ bool Sema::VerifyIntegerConstantExpression(const Expr *E, llvm::APSInt *Result){
|
|||
*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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -546,7 +546,7 @@ bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range,
|
|||
|
||||
// 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 @@ static bool FindConditionalOverload(Sema &Self, Expr *&LHS, Expr *&RHS,
|
|||
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],
|
||||
|
|
|
@ -1379,7 +1379,7 @@ bool Sema::IsUserDefinedConversion(Expr *From, QualType ToType,
|
|||
}
|
||||
|
||||
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 @@ Sema::isBetterOverloadCandidate(const OverloadCandidate& Cand1,
|
|||
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 @@ Sema::BestViableFunction(OverloadCandidateSet& CandidateSet,
|
|||
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 @@ FunctionDecl *Sema::ResolveOverloadedCallFn(Expr *Fn, NamedDecl *Callee,
|
|||
CandidateSet);
|
||||
|
||||
OverloadCandidateSet::iterator Best;
|
||||
switch (BestViableFunction(CandidateSet, Best)) {
|
||||
switch (BestViableFunction(CandidateSet, Fn->getLocStart(), Best)) {
|
||||
case OR_Success:
|
||||
return Best->Function;
|
||||
|
||||
|
@ -3815,7 +3827,7 @@ Sema::OwningExprResult Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc,
|
|||
|
||||
// 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 @@ Sema::CreateOverloadedBinOp(SourceLocation OpLoc,
|
|||
|
||||
// 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 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
|
|||
}
|
||||
|
||||
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 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Object,
|
|||
|
||||
// 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 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc,
|
|||
|
||||
// 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;
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
// RUN: clang -fsyntax-only -Wunused-parameter %s -Xclang -verify
|
||||
|
||||
int f0(int x,
|
||||
int y, // expected-warning{{unused}}
|
||||
int z __attribute__((unused))) {
|
||||
return x;
|
||||
}
|
||||
|
||||
void f1() {
|
||||
(void)^(int x,
|
||||
int y, // expected-warning{{unused}}
|
||||
int z __attribute__((unused))) { return x; };
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
// RUN: clang -fsyntax-only -Wunused -Xclang -verify %s
|
||||
|
||||
@interface foo
|
||||
- (int)meth: (int)x: (int)y: (int)z ;
|
||||
@end
|
||||
|
||||
@implementation foo
|
||||
- (int) meth: (int)x:
|
||||
(int)y: // expected-warning{{unused}}
|
||||
(int) __attribute__((unused))z { return x; }
|
||||
@end
|
Loading…
Reference in New Issue