diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-06-19 23:52:42 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-06-19 23:52:42 +0000 |
commit | e0762c92110dfdcdd207db461a4ea17afd168f1e (patch) | |
tree | ca454873887ffee6570e846ff9e56289360f18f2 | |
parent | 7d5c74ecbbd8719436c071f38657bc8e97ee4a24 (diff) |
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
-rw-r--r-- | include/clang/AST/DeclBase.h | 11 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticGroups.td | 4 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 12 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 18 | ||||
-rw-r--r-- | lib/Frontend/PCHReaderDecl.cpp | 1 | ||||
-rw-r--r-- | lib/Frontend/PCHWriterDecl.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 8 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 22 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 11 | ||||
-rw-r--r-- | lib/Sema/Sema.cpp | 2 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 30 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 13 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 58 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaOverload.cpp | 44 | ||||
-rw-r--r-- | test/Sema/warn-unused-parameters.c | 13 | ||||
-rw-r--r-- | test/SemaObjC/warn-unused-parameters.m | 11 |
20 files changed, 243 insertions, 30 deletions
diff --git a/include/clang/AST/DeclBase.h b/include/clang/AST/DeclBase.h index 811e966172..e2ca1a3298 100644 --- a/include/clang/AST/DeclBase.h +++ b/include/clang/AST/DeclBase.h @@ -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; } diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index ef16b4e69e..2896f7988c 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -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, diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 5b324d87c0..855b7b9d29 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -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">; diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index ba480c5b7c..47583993bc 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -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 diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index d613ae1329..75458d821e 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -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(); diff --git a/lib/Frontend/PCHReaderDecl.cpp b/lib/Frontend/PCHReaderDecl.cpp index 7c477560c6..27a0869632 100644 --- a/lib/Frontend/PCHReaderDecl.cpp +++ b/lib/Frontend/PCHReaderDecl.cpp @@ -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++]); } diff --git a/lib/Frontend/PCHWriterDecl.cpp b/lib/Frontend/PCHWriterDecl.cpp index 55cff663c5..5173ce3312 100644 --- a/lib/Frontend/PCHWriterDecl.cpp +++ b/lib/Frontend/PCHWriterDecl.cpp @@ -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 diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index efabf3a7c6..69152523a1 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -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. diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 389ea666f1..1427814c93 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -279,7 +279,7 @@ Parser::DeclPtrTy Parser::ParseStaticAssertDeclaration(SourceLocation &DeclEnd){ } SourceLocation LParenLoc = ConsumeParen(); - + OwningExprResult AssertExpr(ParseConstantExpression()); if (AssertExpr.isInvalid()) { SkipUntil(tok::semi); diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 3fee78bb71..4a07d05650 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/lib/Parse/ParseExpr.cpp @@ -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); diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 681c6adb2e..87aa5dc671 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -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 ')'. diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 60d8e5f987..e756b41b12 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -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) { diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 23bab23009..230bcffa72 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 @@ 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; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index c4d1fe9983..2dd02af7b9 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -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(); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index fd1cc0406f..8c547cd1cc 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -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; diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index de56819311..692502bbbe 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -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); + } +} + diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 7353efbae7..bec595ca9c 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -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], diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index e81985b74a..11cd5107fc 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -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; diff --git a/test/Sema/warn-unused-parameters.c b/test/Sema/warn-unused-parameters.c new file mode 100644 index 0000000000..115bbab815 --- /dev/null +++ b/test/Sema/warn-unused-parameters.c @@ -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; }; +}
\ No newline at end of file diff --git a/test/SemaObjC/warn-unused-parameters.m b/test/SemaObjC/warn-unused-parameters.m new file mode 100644 index 0000000000..618dc3ff59 --- /dev/null +++ b/test/SemaObjC/warn-unused-parameters.m @@ -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 |