patch: new warning on ODR-use of undefined inline functions

Richard Smith richard at metafoo.co.uk
Thu Jan 31 19:28:54 PST 2013


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.


+++ 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?

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.




More information about the cfe-commits mailing list