/// required.
unsigned Used : 1;
+ /// \brief Whether this declaration was "referenced".
+ /// The difference with 'Used' is whether the reference appears in a
+ /// evaluated context or not, e.g. functions used in uninstantiated templates
+ /// are regarded as "referenced" but not "used".
+ unsigned Referenced : 1;
+
protected:
/// Access - Used by C++ decls for the access specifier.
// NOTE: VC++ treats enums as signed, avoid using the AccessSpecifier enum
Decl(Kind DK, DeclContext *DC, SourceLocation L)
: NextDeclInContext(0), DeclCtx(DC),
Loc(L), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false),
+ HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
Decl(Kind DK, EmptyShell Empty)
: NextDeclInContext(0), DeclKind(DK), InvalidDecl(0),
- HasAttrs(false), Implicit(false), Used(false),
+ HasAttrs(false), Implicit(false), Used(false), Referenced(false),
Access(AS_none), PCHLevel(0), ChangedAfterLoad(false),
IdentifierNamespace(getIdentifierNamespaceForKind(DK)),
HasCachedLinkage(0)
void setUsed(bool U = true) { Used = U; }
+ /// \brief Whether this declaration was referenced.
+ bool isReferenced() const;
+
+ void setReferenced(bool R = true) { Referenced = R; }
+
/// \brief Determine the availability of the given declaration.
///
/// This routine will determine the most restrictive availability of
def UnusedParameter : DiagGroup<"unused-parameter">;
def UnusedValue : DiagGroup<"unused-value">;
def UnusedVariable : DiagGroup<"unused-variable">;
+def UnneededInternalDecl : DiagGroup<"unneeded-internal-declaration">;
+def UnneededMemberFunction : DiagGroup<"unneeded-member-function">;
def UsedButMarkedUnused : DiagGroup<"used-but-marked-unused">;
def ReadOnlySetterAttrs : DiagGroup<"readonly-setter-attrs">;
def Reorder : DiagGroup<"reorder">;
BoolConversions]>,
DiagCategory<"Value Conversion Issue">;
+def Unneeded : DiagGroup<"unneeded",
+ [UnneededInternalDecl
+ //,UnneededMemberFunction (clean-up llvm before enabling)
+ ]>;
+
def Unused : DiagGroup<"unused",
[UnusedArgument, UnusedFunction, UnusedLabel,
// UnusedParameter, (matches GCC's behavior)
// UnusedMemberFunction, (clean-up llvm before enabling)
- UnusedValue, UnusedVariable]>,
+ UnusedValue, UnusedVariable, Unneeded]>,
DiagCategory<"Unused Entity Issue">;
// Format settings.
InGroup<UnusedMemberFunction>, DefaultIgnore;
def warn_used_but_marked_unused: Warning<"%0 was marked unused but was used">,
InGroup<UsedButMarkedUnused>, DefaultIgnore;
+def warn_unneeded_internal_decl : Warning<
+ "%select{function|variable}0 %1 is not needed and will not be emitted">,
+ InGroup<UnneededInternalDecl>, DefaultIgnore;
+def warn_unneeded_member_function : Warning<
+ "member function %0 is not needed and will not be emitted">,
+ InGroup<UnneededMemberFunction>, DefaultIgnore;
def warn_parameter_size: Warning<
"%0 is a large (%1 bytes) pass-by-value argument; "
return false;
}
+bool Decl::isReferenced() const {
+ if (Referenced)
+ return true;
+
+ // Check redeclarations.
+ for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I)
+ if (I->Referenced)
+ return true;
+
+ return false;
+}
+
/// \brief Determine the availability of the given declaration based on
/// the target platform.
///
DiagD = FD;
if (DiagD->isDeleted())
continue; // Deleted functions are supposed to be unused.
- Diag(DiagD->getLocation(),
- isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
- : diag::warn_unused_function)
- << DiagD->getDeclName();
+ if (DiagD->isReferenced()) {
+ if (isa<CXXMethodDecl>(DiagD))
+ Diag(DiagD->getLocation(), diag::warn_unneeded_member_function)
+ << DiagD->getDeclName();
+ else
+ Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
+ << /*function*/0 << DiagD->getDeclName();
+ } else {
+ Diag(DiagD->getLocation(),
+ isa<CXXMethodDecl>(DiagD) ? diag::warn_unused_member_function
+ : diag::warn_unused_function)
+ << DiagD->getDeclName();
+ }
} else {
const VarDecl *DiagD = cast<VarDecl>(*I)->getDefinition();
if (!DiagD)
DiagD = cast<VarDecl>(*I);
- Diag(DiagD->getLocation(), diag::warn_unused_variable)
- << DiagD->getDeclName();
+ if (DiagD->isReferenced()) {
+ Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl)
+ << /*variable*/1 << DiagD->getDeclName();
+ } else {
+ Diag(DiagD->getLocation(), diag::warn_unused_variable)
+ << DiagD->getDeclName();
+ }
}
}
void Sema::MarkDeclarationReferenced(SourceLocation Loc, Decl *D) {
assert(D && "No declaration?");
+ D->setReferenced();
+
if (D->isUsed(false))
return;
Var->setAccess(D->getAccess());
- if (!D->isStaticDataMember())
+ if (!D->isStaticDataMember()) {
Var->setUsed(D->isUsed(false));
+ Var->setReferenced(D->isReferenced());
+ }
// FIXME: In theory, we could have a previous declaration for variables that
// are not static data members.
}
D->setImplicit(Record[Idx++]);
D->setUsed(Record[Idx++]);
+ D->setReferenced(Record[Idx++]);
D->setAccess((AccessSpecifier)Record[Idx++]);
D->setPCHLevel(Record[Idx++] + (F.Type <= ASTReader::PCH));
}
Writer.WriteAttributes(D->getAttrs(), Record);
Record.push_back(D->isImplicit());
Record.push_back(D->isUsed(false));
+ Record.push_back(D->isReferenced());
Record.push_back(D->getAccess());
Record.push_back(D->getPCHLevel());
}
Abv->Add(BitCodeAbbrevOp(0)); // HasAttrs
Abv->Add(BitCodeAbbrevOp(0)); // isImplicit
Abv->Add(BitCodeAbbrevOp(0)); // isUsed
+ Abv->Add(BitCodeAbbrevOp(0)); // isReferenced
Abv->Add(BitCodeAbbrevOp(AS_none)); // C++ AccessSpecifier
Abv->Add(BitCodeAbbrevOp(0)); // PCH level
-// RUN: %clang_cc1 -fsyntax-only -Wunused-function -verify %s
+// RUN: %clang_cc1 -fsyntax-only -Wunused-function -Wunneeded-internal-declaration -verify %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wunused %s
// RUN: %clang_cc1 -fsyntax-only -verify -Wall %s
static void f2() {}
static void f1() {f2();} // expected-warning{{unused}}
-static int f0() { return 17; } // expected-warning{{unused}}
+static int f0() { return 17; } // expected-warning{{not needed and will not be emitted}}
int x = sizeof(f0());
static void f3();
static void f12(void);
// PR7923
-static void unused(void) { unused(); } // expected-warning{{unused}}
+static void unused(void) { unused(); } // expected-warning{{not needed and will not be emitted}}
// rdar://8728293
static void cleanupMalloc(char * const * const allocation) { }
void test(A a); // expected-warning {{unused function}}
extern "C" void test4(A a);
}
+
+namespace rdar8733476 {
+ static void foo() { } // expected-warning {{not needed and will not be emitted}}
+
+ template <int>
+ void bar() {
+ foo();
+ }
+}