<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Feb 10, 2015 at 12:40 PM, Aaron Ballman <span dir="ltr"><<a href="mailto:aaron@aaronballman.com" target="_blank">aaron@aaronballman.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Wed, Jan 14, 2015 at 10:31 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>> wrote:<br>
> +  friend struct llvm::DenseMapInfo <QualTypeExt>;<br>
><br>
> Extra space before <.<br>
><br>
> +// It's OK to treat BaseSubobject as a POD type.<br>
><br>
> Typo: BaseSubobject should be QualTypeExt.<br>
<br>
</span>I've fixed both those up locally.<br>
<span class=""><br>
><br>
> +        // Add direct base classes to the list of types to be checked.<br>
> [...]<br>
> +        RD->lookupInBases(<br>
><br>
> lookupInBases finds all bases, not just the direct ones.<br>
<br>
</span>I must be missing something, because that doesn't seem to be entirely<br>
workable. When the callback function passed to lookupInBases returns<br>
true, searching along that path stops. See CXXInheritance.cpp:251; if<br>
BaseMatches returns true, we record the path but never visit further<br>
bases.<br>
<br>
That winds up being problematic for situations like:<br>
<br>
struct B {};<br>
struct D : B {};<br>
struct D2 : D {};<br>
<br>
void f6() {<br>
  try {<br>
  } catch (B &b) {  // expected-note {{for type 'HandlerInversion::B &'}}<br>
  } catch (D2 &d) {  // expected-warning {{exception of type<br>
'HandlerInversion::D2 &' will be caught by earlier handler}}<br>
  }<br>
}<br>
<br>
We process the handler for B& and add it to the map. Then we process<br>
the handler for D2&. When we call lookupInBases on D2, we find D<br>
first, and since it's access is public, the callback returns true. The<br>
callback is not called a subsequent time for B as a base of D, and so<br>
we wind up failing to warn in that case.<br>
<br>
Changing that "else if" to be an "if" is the wrong thing to do as<br>
well, because then a bunch of regression tests fail. I can kind of<br>
hack the behavior I want by having my callback not be a lambda, and<br>
call lookupInBases on the base class prior to returning true, but it<br>
feels like I'm doing something wrong. Ideas?<br></blockquote><div><br></div><div>In Frobble, I think you should return true if you find a public path to a HandledType, not just if you find a public base class.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
I've attached a WIP that attempts to capture what you're suggesting<br>
below, but it's also causing problems with<br>
test\SemaCXX\unreachable-catch-clauses.cpp reporting the warning for<br>
the final handler twice, so it's not ready yet. Is this moving in the<br>
direction you were thinking (aside from obvious issues like the<br>
callback being named Frobble)?</blockquote><div><br></div><div>Yes, thanks.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
> You should be able<br>
> to do something like this:<br>
><br>
> 1) If the type is a class type, call lookupInBases, and check none of the<br>
> public unambiguous bases are in the map.<br>
> 2) Add the type itself to the map and diagnose if it was already there.<br>
><br>
> (and remove your explicit queue of types to process).<br>
><br>
><br>
> --- test/CXX/drs/dr3xx.cpp (revision 222171)<br>
> +++ test/CXX/drs/dr3xx.cpp (working copy)<br>
> @@ -170,9 +170,9 @@<br>
>    void f() {<br>
>      try {<br>
>        throw D();<br>
> -    } catch (const A&) {<br>
> +    } catch (const A&) { // expected-note {{for type 'const dr308::A &'}}<br>
>        // unreachable<br>
> -    } catch (const B&) {<br>
> +    } catch (const B&) { // expected-warning {{exception of type 'const<br>
> dr308::B &' will be caught by earlier handler}}<br></span></blockquote><div><br></div><div>Hmm, while we're here, it'd be good to strip off the 'const' and '&' from this diagnostic; you can't get an exception object of reference type.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">
>        // get here instead<br>
>      }<br>
>    }<br>
><br>
> Yikes, the warning is sort of a false-positive here! (The text of the<br>
> warning is true, but the 'throw D()' will actually be caught by the second<br>
> handler, because A is an ambiguous base of D).<br>
<br>
</span>Oye, that is basically a false positive, and I'm not certain there's<br>
much I could realistically do about it either. :-(<br>
<br>
Thanks!<br>
<span class="HOEnZb"><font color="#888888"><br>
~Aaron<br>
</font></span><div class="HOEnZb"><div class="h5"><br>
><br>
> On Thu, Dec 4, 2014 at 7:23 AM, Aaron Ballman <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>><br>
> wrote:<br>
>><br>
>> Ping<br>
>><br>
>> On Tue, Nov 25, 2014 at 9:59 AM, Aaron Ballman <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>><br>
>> wrote:<br>
>> > Ping<br>
>> ><br>
>> > On Mon, Nov 17, 2014 at 4:15 PM, Aaron Ballman <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>><br>
>> > wrote:<br>
>> >> On Fri, Nov 14, 2014 at 5:36 PM, Richard Smith <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>><br>
>> >> wrote:<br>
>> >>> On Fri, Nov 14, 2014 at 7:55 AM, Aaron Ballman<br>
>> >>> <<a href="mailto:aaron@aaronballman.com">aaron@aaronballman.com</a>><br>
>> >>> wrote:<br>
>> >>>><br>
>> >>>> On Thu, Nov 13, 2014 at 10:06 PM, Richard Smith<br>
>> >>>> <<a href="mailto:richard@metafoo.co.uk">richard@metafoo.co.uk</a>><br>
>> >>>> wrote:<br>
>> >>>> > +    std::list<QualType> BaseClassTypes;<br>
>> >>>> ><br>
>> >>>> > This will allocate memory for every node; it would be better to use<br>
>> >>>> > a<br>
>> >>>> > SmallVector here (and use a depth-first search rather than a<br>
>> >>>> > breadth-first<br>
>> >>>> > one so you're only modifying one end of your list).<br>
>> >>>> ><br>
>> >>>> > +    for (auto &CurType : BaseClassTypes) {<br>
>> >>>> ><br>
>> >>>> > It's a bit scary to be iterating over your container while<br>
>> >>>> > modifying it<br>
>> >>>> > (even though it's actually correct in this case). Alternative<br>
>> >>>> > idiom:<br>
>> >>>> ><br>
>> >>>> > SmallVector<QualType, 8> BaseClassTypes;<br>
>> >>>> > BaseClassTypes.push_back(...);<br>
>> >>>> > while (!BaseClassTypes.empty()) {<br>
>> >>>> >   QualType T = BaseClassTypes.pop_back_val();<br>
>> >>>> >   // ... maybe push back some values.<br>
>> >>>> > }<br>
>> >>>><br>
>> >>>> I have a strong preference for your idiom. ;-)<br>
>> >>>><br>
>> >>>> ><br>
>> >>>> > +      auto I = std::find_if(<br>
>> >>>> > +          HandledTypes.begin(), HandledTypes.end(),<br>
>> >>>> ><br>
>> >>>> > This is still quadratic-time; maybe use a DenseMap with the<br>
>> >>>> > canonical<br>
>> >>>> > QualType plus a "was it a pointer" flag as a key?<br>
>> >>>><br>
>> >>>> I've given this a shot in my latest patch. Thank you for the<br>
>> >>>> feedback!<br>
>> >>><br>
>> >>><br>
>> >>>  +  unsigned IsReference : 1;<br>
>> >>><br>
>> >>> I think we don't need / want an IsReference flag. Consider:<br>
>> >>><br>
>> >>>   try { throw Derived(); }<br>
>> >>>   catch (Base) {}<br>
>> >>>   catch (Derived &d) {}<br>
>> >>><br>
>> >>> The second catch handler is unreachable even though we have a by<br>
>> >>> reference/by value mismatch.<br>
>> >><br>
>> >> That's a very good point. Thanks! I've added an additional test for<br>
>> >> that case.<br>
>> >><br>
>> >>><br>
>> >>><br>
>> >>> +      QualType Underlying = CurType.underlying();<br>
>> >>> +      if (auto *RD = Underlying->getAsCXXRecordDecl()) {<br>
>> >>> +        for (const auto &B : RD->bases())<br>
>> >>> +          BaseClassTypes.push_back(QualTypeExt(B.getType(),<br>
>> >>> CurType.isPointer(),<br>
>> >>> +<br>
>> >>> CurType.isReference()));<br>
>> >>><br>
>> >>> Per [except.handle]p1, you should only consider public, unambiguous<br>
>> >>> base<br>
>> >>> classes here. Rather than walk the base classes yourself, you could<br>
>> >>> use<br>
>> >>> CXXRecordDecl::lookupInBases to enumerate the base classes and paths,<br>
>> >>> and<br>
>> >>> then check the public unambiguous ones.<br>
>> >><br>
>> >> I've made this change in the attached patch. Additionally, this patch<br>
>> >> no longer pays attention to exception declarations that are invalid,<br>
>> >> such as can be had from using auto in a catch clause.<br>
>> >><br>
>> >> Thanks!<br>
>> >><br>
>> >> ~Aaron<br>
><br>
><br>
</div></div></blockquote></div><br></div></div>