patch: new warning on ODR-use of undefined inline functions
Richard Smith
richard at metafoo.co.uk
Fri Feb 1 00:09:27 PST 2013
LGTM
On Thu, Jan 31, 2013 at 11:39 PM, Nick Lewycky <nlewycky at google.com> wrote:
> 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
>
>
More information about the cfe-commits
mailing list