[patch] Implementing -Wunused-local-typedefs

Richard Smith richard at metafoo.co.uk
Fri Jun 27 08:56:12 PDT 2014


On Tue, Jun 24, 2014 at 9:55 AM, Nico Weber <thakis at chromium.org> wrote:

> On Tue, May 6, 2014 at 6:01 PM, Richard Smith <richard at metafoo.co.uk>
> wrote:
>
>>  def UnusedConstVariable : DiagGroup<"unused-const-variable">;
>>  def UnusedVariable : DiagGroup<"unused-variable",
>>                                 [UnusedConstVariable]>;
>> +def UnusedLocalTypedefs : DiagGroup<"unused-local-typedefs">;
>>  def UnusedPropertyIvar :  DiagGroup<"unused-property-ivar">;
>>
>> I'm a little uncomfortable about this flag being plural and the others
>> being singular. GCC compatible, you say? =(
>>
>>
>> +def warn_unused_local_typedefs : Warning<"unused typedef %0">,
>>
>> This one should definitely be singular.
>>
>> Reformatting of lib/Parse/ParseExprCXX.cpp looks unrelated. Feel free to
>> commit that separately.
>>
>> +    if (TypedefDecl* TD = dyn_cast_or_null<TypedefDecl>(SD))
>>
>> * should go on the right. Also, use 'auto' for a variable initialized
>> from cast/dyn_cast/etc.
>>
>> Rather than calling setReferenced directly, please call
>> Sema::MarkAnyDeclReferenced.
>>
>>  +static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D,
>> +                                     const DeclContext *DC) {
>> [...]
>>  +  if (!DC->isFunctionOrMethod())
>> +    return false;
>>
>> Please document what 'DC' is here; it's really not obvious. But it seems
>> to me that you can replace DC here and below with just a bool
>> WithinFunction. You can also remove it entirely and check whether
>> D->getDeclContext() is a function, method, or local class.
>>
>> +void Sema::DiagnoseUnusedDecl(const NamedDecl *D, const DeclContext *DC)
>> {
>> +  if (DC->isFunctionOrMethod())
>> +    if (const RecordDecl *RD = dyn_cast<RecordDecl>(D))
>> +      for (auto *TmpD : RD->decls())
>> +        if (isa<TypedefDecl>(TmpD) || isa<RecordDecl>(TmpD))
>> +          DiagnoseUnusedDecl(cast<NamedDecl>(TmpD), DC);
>>
>> This would make more sense as a layer between ActOnPopScope and
>> DiagnoseUnusedDecl. A comment explaining why we only do this within a
>> function or method would help ("within a function or method, we defer these
>> checks until the end of the surrounding scope").
>>
>> Also, this isn't necessarily correct in C++14, since a local type's
>> members can be first used once we've already left the function:
>>
>>   auto f() {
>>     struct S { typedef int t; };
>>     return S();
>>   }
>>   auto x = f();
>>   decltype(x)::t y;
>>
>> What happens if the local type is used as an argument to a function
>> template, which in turn uses the typedef? Can we really diagnose this
>> before end-of-TU?
>>
>
> Sneaky! gcc gets this wrong too (filed
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61596). This kills the
> "local-" part of the warning.
>
> Is diagnosing this at end of TU fine? I vaguely recall that a concern with
> -Wunused-private-field was that it forced deserialization of many ast nodes
> (?); would that be a concern here too?
>

Generally, yes, it would. The difference here is that we never want to
diagnose unused typedefs that are defined in a module, so we can choose to
just not serialize the list in that case.


>
>
>>
>> +  else if (isa<TypedefDecl>(D))  // TODO: Warn on unused c++11 aliases
>> too?
>> +    DiagID = diag::warn_unused_local_typedefs;
>>
>> Yes, please change this to TypedefNameDecl (throughout the patch). It
>> doesn't make sense to handle these differently, since one can be a
>> redeclaration of the other.
>>
>> Index: lib/Sema/SemaTemplateInstantiateDecl.cpp
>> ===================================================================
>>  --- lib/Sema/SemaTemplateInstantiateDecl.cpp (revision 207920)
>> +++ lib/Sema/SemaTemplateInstantiateDecl.cpp (working copy)
>> @@ -3651,7 +3651,7 @@
>>    if (!NewVar->isInvalidDecl() &&
>>        NewVar->getDeclContext()->isFunctionOrMethod() &&
>> !NewVar->isUsed() &&
>>        OldVar->getType()->isDependentType())
>> -    DiagnoseUnusedDecl(NewVar);
>> +    DiagnoseUnusedDecl(NewVar, NewVar->getDeclContext());
>>
>> Hmm, why do we diagnose unused decls from template instantiation at all?
>>
>> On Sat, May 3, 2014 at 10:37 PM, Nico Weber <thakis at chromium.org> wrote:
>>
>>> With one more setReferenced() call (in SemaCXXScopeSpec.cpp). This
>>> version has successfully compiled several thousand files of chromium
>>> (all that I've tried so far).
>>>
>>> On Sat, May 3, 2014 at 6:35 PM, Nico Weber <thakis at chromium.org> wrote:
>>> > About point 2: The patch currently incorrectly warns on the "v"
>>> typedef in:
>>> >
>>> >   template <class T> struct V { typedef int iterator; };
>>> >   void f() {
>>> >     typedef V<int> v;
>>> >     v::iterator it;
>>> >   }
>>> >
>>> > So there's at least one more place where I need to insert a
>>> > setReferenced() I'll send an updated version once I found where, but
>>> > I'm thankful for comments on the overall approach in the meantime too.
>>> >
>>> > On Sat, May 3, 2014 at 6:08 PM, Nico Weber <thakis at chromium.org>
>>> wrote:
>>> >> (Forgot to say: This is also PR18265.)
>>> >>
>>> >> On Sat, May 3, 2014 at 6:07 PM, Nico Weber <thakis at chromium.org>
>>> wrote:
>>> >>> Hi,
>>> >>>
>>> >>> gcc has a warning -Wunused-local-typedefs that warns on unused local
>>> >>> typedefs. Inspired by r207870, I thought it'd be nice if clang had
>>> >>> this warning too. This warning requires the following three things:
>>> >>>
>>> >>>
>>> >>> 1.) A bit to track if a typedef has been referenced.
>>> >>>
>>> >>> Decl already has isUsed and isReferenced, but they don't seem to be
>>> >>> used for TypedefDecls, so I'm just using isReferenced on TypedefDecls
>>> >>> for this.
>>> >>>
>>> >>>
>>> >>> 2.) Setting that bit on typedefs that are used.
>>> >>>
>>> >>> The three strategies I can think of:
>>> >>> a.) Do this in Sema::DiagnoseUseOfDecl(), this seems to be already
>>> >>> called for decls all over the place, and an "if isa<TypedefDecl>(D)
>>> >>> D->setReferenced()" seems to do the trick.
>>> >>> b.) Do this in LookupName
>>> >>> c.) Do this explicitly in the places where it's actually necessary.
>>> >>>
>>> >>> The attached patch goes with the last approach. The three places I
>>> >>> found where it's needed are Sema::getTypeName(),
>>> Sema::ClassifyName(),
>>> >>> and Sema::LookupInlineAsmField(). The first two are called by the
>>> >>> parser for almost everything, while the third is called for
>>> references
>>> >>> to structs from MS inline assembly. That last one is a bit scary as
>>> it
>>> >>> means it's possible that there are other places this is needed that I
>>> >>> missed.
>>> >>>
>>> >>>
>>> >>> 3.) A way to check all typedefs in a scope when that scope ends.
>>> >>>
>>> >>> I added this to Sema::ActOnPopScope() which is where the
>>> >>> unused-variable and unused-label warnings are created. This works
>>> >>> well, but to catch the unused local typedef in
>>> >>>
>>> >>>   {
>>> >>>     struct A {
>>> >>>       struct B { typedef int SoDeep; };
>>> >>>     };
>>> >>>   }
>>> >>>
>>> >>> it means that that code now needs to recurse into all RecordDecl in a
>>> >>> scope, which it didn't need to do previously.
>>> >>>
>>> >>>
>>> >>> Let me know how badly I've chosen in each instance :-)
>>> >>>
>>> >>> Thanks,
>>> >>> Nico
>>> >>>
>>> >>> ps: If this goes in, a follow-up question is if this should warn on
>>> >>> unused C++11 type aliases too – it'd just require
>>> >>> s/TypedefDecl/TypedefNameDecl/ in two places in the patch, so it
>>> >>> should be an easy follow-up.
>>>
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140627/acbf9950/attachment.html>


More information about the cfe-commits mailing list