diff options
author | Nick Lewycky <nicholas@mxc.ca> | 2013-02-01 08:13:20 +0000 |
---|---|---|
committer | Nick Lewycky <nicholas@mxc.ca> | 2013-02-01 08:13:20 +0000 |
commit | cd0655b17249c4c4908ca91462657f62285017e6 (patch) | |
tree | f591e7ddc3ef7fdc95b065a9ae56a34d7b42c906 /lib/Sema/Sema.cpp | |
parent | be507b6e72df8ab5e7d8c31eb4453e1bdf5fcfaf (diff) |
Add a new -Wundefined-inline warning for inline functions which are used but not
defined. Fixes PR14993!
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@174158 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/Sema.cpp')
-rw-r--r-- | lib/Sema/Sema.cpp | 54 |
1 files changed, 34 insertions, 20 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 76ea996ec5..5e5011b7f6 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -366,12 +366,16 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { } namespace { - struct SortUndefinedInternal { + struct SortUndefinedButUsed { const SourceManager &SM; - explicit SortUndefinedInternal(SourceManager &SM) : SM(SM) {} + explicit SortUndefinedButUsed(SourceManager &SM) : SM(SM) {} bool operator()(const std::pair<NamedDecl *, SourceLocation> &l, const std::pair<NamedDecl *, SourceLocation> &r) const { + if (l.second.isValid() && !r.second.isValid()) + return true; + if (!l.second.isValid() && r.second.isValid()) + return false; if (l.second != r.second) return SM.isBeforeInTranslationUnit(l.second, r.second); return SM.isBeforeInTranslationUnit(l.first->getLocation(), @@ -381,55 +385,65 @@ namespace { } /// Obtains a sorted list of functions that are undefined but ODR-used. -void Sema::getUndefinedInternals( +void Sema::getUndefinedButUsed( SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) { for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator - I = UndefinedInternals.begin(), E = UndefinedInternals.end(); + I = UndefinedButUsed.begin(), E = UndefinedButUsed.end(); I != E; ++I) { NamedDecl *ND = I->first; // Ignore attributes that have become invalid. if (ND->isInvalidDecl()) continue; - // If we found out that the decl is external, don't warn. - if (ND->getLinkage() == ExternalLinkage) continue; - // __attribute__((weakref)) is basically a definition. if (ND->hasAttr<WeakRefAttr>()) continue; if (FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { if (FD->isDefined()) continue; + if (FD->getLinkage() == ExternalLinkage && + !FD->getMostRecentDecl()->isInlined()) + continue; } else { if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly) continue; + if (ND->getLinkage() == ExternalLinkage) + continue; } Undefined.push_back(std::make_pair(ND, I->second)); } - // Sort (in order of use site) so that we're not (as) dependent on - // the iteration order through an llvm::DenseMap. + // Sort (in order of use site) so that we're not dependent on the iteration + // order through an llvm::DenseMap. std::sort(Undefined.begin(), Undefined.end(), - SortUndefinedInternal(Context.getSourceManager())); + SortUndefinedButUsed(Context.getSourceManager())); } -/// checkUndefinedInternals - Check for undefined objects with internal linkage. -static void checkUndefinedInternals(Sema &S) { - if (S.UndefinedInternals.empty()) return; +/// checkUndefinedButUsed - Check for undefined objects with internal linkage +/// or that are inline. +static void checkUndefinedButUsed(Sema &S) { + if (S.UndefinedButUsed.empty()) return; // Collect all the still-undefined entities with internal linkage. SmallVector<std::pair<NamedDecl *, SourceLocation>, 16> Undefined; - S.getUndefinedInternals(Undefined); + S.getUndefinedButUsed(Undefined); if (Undefined.empty()) return; for (SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> >::iterator I = Undefined.begin(), E = Undefined.end(); I != E; ++I) { NamedDecl *ND = I->first; - S.Diag(ND->getLocation(), diag::warn_undefined_internal) - << isa<VarDecl>(ND) << ND; - S.Diag(I->second, diag::note_used_here); + if (ND->getLinkage() != ExternalLinkage) { + S.Diag(ND->getLocation(), diag::warn_undefined_internal) + << isa<VarDecl>(ND) << ND; + } else { + assert(cast<FunctionDecl>(ND)->getMostRecentDecl()->isInlined() && + "used object requires definition but isn't inline or internal?"); + S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; + } + if (I->second.isValid()) + S.Diag(I->second, diag::note_used_here); } } @@ -743,8 +757,8 @@ void Sema::ActOnEndOfTranslationUnit() { } if (ExternalSource) - ExternalSource->ReadUndefinedInternals(UndefinedInternals); - checkUndefinedInternals(*this); + ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); + checkUndefinedButUsed(*this); } if (Diags.getDiagnosticLevel(diag::warn_unused_private_field, @@ -1088,7 +1102,7 @@ void ExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl<NamespaceDecl *> &Namespaces) { } -void ExternalSemaSource::ReadUndefinedInternals( +void ExternalSemaSource::ReadUndefinedButUsed( llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) { } |