<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Wed, Oct 29, 2014 at 6:10 AM, Brad King <span dir="ltr"><<a href="mailto:brad.king@kitware.com" target="_blank">brad.king@kitware.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><span class="">On 10/28/2014 05:46 PM, Richard Smith wrote:<br>
> Right; that's how the C++ standard says SFINAE works.<br>
<br>
</span>Sure, but I'm not performing a SFINAE test.  That's why SFINAETrap is not<br>
sufficient.  I'm not trying to replace SFINAETrap.  I'm trying to provide<br>
a new primitive that is useful to tools based on Clang to achieve things<br>
that are currently not possible.<br>
<span class=""><br>
> if you suppress errors here, things will go wrong later<br>
> (later tests which happen to look at validity of the same thing can<br>
> get incorrect answers).<br>
<br>
</span>IIUC a declaration that has been marked invalid is considered to not exist<br>
by such later tests.  See below.<br>
<span class=""><br>
> The problem is with a case like:<br>
><br>
> template<typename T> struct A {<br>
>   A() { T::error; }<br>
> };<br>
> struct B : A<int> {};<br>
> struct C : A<int> {};<br>
><br>
> Trying to create B::B() will trigger the instantiation of A<int>::A(),<br>
> which will fail with a non-local error. We'll mark the function as invalid,<br>
> and you'll determine that B::B() doesn't work. Then you'll try C::C(),<br>
> which will *succeed*, because we'll silently skip A<int>::A() because we've<br>
> already marked it invalid.<br>
<br>
</span>Clang calls setInvalidDecl on A::A() after failing to instantiate it for<br>
B::B().  Then C::C() fails too because A::A() does not exist anymore.<br></blockquote><div><br></div><div>OK, I can reproduce that behavior for a testcase like:</div><div><br></div><div><div>template<typename T> struct A {</div><div>  A() { T::error; }</div><div>};</div><div>struct B : A<int> {};</div><div>template<typename T> struct C : A<T> { C() : A<int>() {} };</div><div>B b; C<int> c;</div></div><div><br></div><div>We produce:</div><div><br></div><div><div><stdin>:2:9: error: type 'int' cannot be used prior to '::' because it has no members</div><div>  A() { T::error; }</div><div>        ^</div><div><stdin>:4:8: note: in instantiation of member function 'A<int>::A' requested here</div><div>struct B : A<int> {};</div><div>       ^</div><div><stdin>:5:46: error: no matching constructor for initialization of 'A<int>'</div><div>template<typename T> struct C : A<T> { C() : A<int>() {} };</div><div>                                             ^</div><div><stdin>:6:13: note: in instantiation of member function 'C<int>::C' requested here</div><div>B b; C<int> c;</div><div>            ^</div><div><stdin>:1:29: note: candidate constructor (the implicit copy constructor) not viable: requires 1 argument, but 0 were provided</div><div>template<typename T> struct A {</div><div>                            ^</div></div><div><br></div><div>This is a bug; we should not produce the second error message.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
I hacked my tool to take out the DiagnosticSuppressionScope for the<br>
DefaultConstructor case and to print out a description of each implicit<br>
member before attempting to define it.  The result on the above code is:<br>
<br>
--------------------------------------------------------------------------<br>
DefaultConstructor: B<br>
test.cpp:2:9: error: type 'int' cannot be used prior to '::' because it has<br>
      no members<br>
  A() { T::error; }<br>
        ^<br>
test.cpp:4:8: note: in instantiation of member function 'A<int>::A' requested<br>
      here<br>
struct B : A<int> {};<br>
       ^<br>
DefaultConstructor: C<br>
test.cpp:5:8: error: implicit default constructor for 'C' must explicitly<br>
      initialize the base class 'A<int>' which does not have a default<br>
      constructor<br>
struct C : A<int> {};<br>
       ^<br>
--------------------------------------------------------------------------<br>
<br>
One can see that both B::B() and C::C() get errors as desired.</blockquote><div><br></div><div>That is not guaranteed, and will no longer be the case when we fix the bug described above.</div></div></div></div>