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/SemaDecl.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/SemaDecl.cpp')
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 32 |
1 files changed, 27 insertions, 5 deletions
diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 4404c6f9a0..0d549fcc18 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2215,6 +2215,23 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { New->setType(QualType(NewType, 0)); NewQType = Context.getCanonicalType(New->getType()); } + + // If this redeclaration makes the function inline, we may need to add it to + // UndefinedButUsed. + if (!Old->isInlined() && New->isInlined() && + !New->hasAttr<GNUInlineAttr>() && + (getLangOpts().CPlusPlus || !getLangOpts().GNUInline) && + Old->isUsed(false) && + !Old->isDefined() && !New->isThisDeclarationADefinition()) + UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(), + SourceLocation())); + + // If this redeclaration makes it newly gnu_inline, we don't want to warn + // about it. + if (New->hasAttr<GNUInlineAttr>() && + Old->isInlined() && !Old->hasAttr<GNUInlineAttr>()) { + UndefinedButUsed.erase(Old->getCanonicalDecl()); + } if (getLangOpts().CPlusPlus) { // (C++98 13.1p2): @@ -8431,12 +8448,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); - // The only way to be included in UndefinedInternals is if there is an - // ODR-use before the definition. Avoid the expensive map lookup if this + // The only way to be included in UndefinedButUsed is if there is an + // ODR use before the definition. Avoid the expensive map lookup if this // is the first declaration. - if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed() && - FD->getLinkage() != ExternalLinkage) - UndefinedInternals.erase(FD); + if (FD->getPreviousDecl() != 0 && FD->getPreviousDecl()->isUsed()) { + if (FD->getLinkage() != ExternalLinkage) + UndefinedButUsed.erase(FD); + else if (FD->isInlined() && + (LangOpts.CPlusPlus || !LangOpts.GNUInline) && + (!FD->getPreviousDecl()->hasAttr<GNUInlineAttr>())) + UndefinedButUsed.erase(FD); + } // If the function implicitly returns zero (like 'main') or is naked, // don't complain about missing return statements. |