patch: new warning on ODR-use of undefined inline functions
Nick Lewycky
nlewycky at google.com
Thu Jan 31 23:39:08 PST 2013
On 31 January 2013 19:28, Richard Smith <richard at metafoo.co.uk> wrote:
> On Thu, Jan 31, 2013 at 6:34 PM, Nick Lewycky <nlewycky at google.com> wrote:
> > On 30 January 2013 22:43, Richard Smith <richard at metafoo.co.uk> wrote:
> >>
> >> SortUndefinedButUsed is not a strict weak ordering. Consider:
> >>
> >> A = {1, invalid}
> >> B = {2, 1}
> >> C = {0, 2}
> >>
> >> We have A < B (comparing first because A.second is invalid), B < C
> >> (comparing second), and C < A (comparing first because A.second is
> >> invalid).
> >
> >
> > Fixed. Thanks for catching that.
> >
> >> @@ -8428,12 +8436,12 @@
> >> if (FD) {
> >> FD->setBody(Body);
> >>
> >> - // The only way to be included in UndefinedInternals is if there is
> >> an
> >> + // 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 && !FD->isInlined())
> >> + UndefinedButUsed.erase(FD);
> >>
> >> Shouldn't this be (FD->getLinkage() != ExternalLinkage ||
> >> FD->getPreviousDecl()->isInlined()) ?
> >
> >
> > Right.
> >
> >> +namespace test7 {
> >> + // It is invalid to redeclare a function inline after its definition,
> >> but we
> >> + // do not diagnose this yet.
> >> + void f(); // expected-warning{{inline function 'test7::f' is not
> >> defined}}
> >> + void test() { f(); } // no used-here note.
> >> + inline void f();
> >> +}
> >>
> >> This test doesn't redeclare a function inline after its definition,
> >> just after its use.
> >
> >
> > Erp, of course. Removed the stale comment.
> >
> >> On Wed, Jan 30, 2013 at 10:19 PM, Nick Lewycky <nlewycky at google.com>
> >> wrote:
> >> > This patch extends the tracking for used but undefined functions and
> >> > variables with internal linkage to also apply to inline functions.
> >> > Sema::UndefinedInternals is renamed Sema::UndefinedButUsed.
> >> >
> >> > Fixes PR14993. Please review! Please pay particular attention to the
> >> > behaviour of the error under C99 and GNU89 modes.
> >>
> >> I've not looked at this from the perspective of C yet, but it looks
> >> correct for C++ (modulo the above comments).
> >
> >
> > C99 has a similar rule:
> >
> > "For a function with external linkage, the following restrictions
> apply:
> > If a function is declared with an inline function specifier, then it shall
> > also be defined in the same translation unit."
> > - C99 6.7.4p6
> >
> > Of course, a function with internal linkage and isn't covered by the
> above,
> > but it doesn't matter since that's invalid for other reasons. Good news,
> in
> > C99 mode GCC warns on declaration without definition of 'inline',
> 'extern
> > inline' functions, and used but undefined 'static inline' functions.
> >
> > Bad news, GNU89 mode seems to permit it. 'static inline' functions get
> the
> > same warning as in C99 mode, but in practice you can define a function of
> > the same name in another TU, without 'static inline', and it links fine.
> > With 'extern inline' I think it's even deliberate.
> >
> > I've changed the patch to simply not warn on used but not defined
> > gnu89-inline functions.
>
> OK, fair enough.
>
>
> @@ -366,13 +366,17 @@
> }
>
> 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 != r.second)
> + if (l.second.isValid() && !r.second.isValid())
> + return true;
> + if (!l.second.isValid() && r.second.isValid())
> + return false;
> + if (l.second != r.second && l.second.isValid() &&
> r.second.isValid())
>
> I think you can drop the && l.second.isValid() && r.second.isValid()
> here -- invalid source locations compare equal.
>
Done.
+++ lib/Sema/SemaDecl.cpp (working copy)
> @@ -2215,6 +2215,14 @@
> 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() &&
> + Old->isUsed(false) &&
> + !Old->isDefined() && !New->isThisDeclarationADefinition())
> + UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(),
> + SourceLocation()));
>
> Do you need a GNU inline check here?
>
Yep.
Also, what happens if a redeclaration adds the gnu_inline attribute to
> a function which is already declared inline? In g++ that's an error,
> but Clang appears to allow it.
>
Yep again. See the new tests!
Nick
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130131/6f6a9920/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: undefined-but-used-3.patch
Type: application/octet-stream
Size: 20261 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20130131/6f6a9920/attachment.obj>
More information about the cfe-commits
mailing list