<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Tue, Oct 28, 2014 at 10:56 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:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On 10/28/2014 01:35 PM, Richard Smith wrote:<br>
> How does this compare to Sema's existing SFINAETrap mechanism?<br>
<br>
</span>It is more general than SFINAETrap.<br>
<br>
I originally tried that but it is insufficient.  Inside any template<br>
instantiation Sema::InstantiatingTemplate::Initialize always sets<br>
InNonInstantiationSFINAEContext to false so Sema::isSFINAEContext<br>
returns None and SFINAETrap does not suppress the error.</blockquote><div><br></div><div>Right; that's how the C++ standard says SFINAE works. Also, we do not recover from those errors in a way that would let you blindly continue parsing: if you suppress errors here, things will go wrong later (later tests which happen to look at validity of the same thing can get incorrect answers).</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Also I<br>
want to suppress all errors, not just those tolerated by SFINAE.<br>
<span class=""><br>
> What happens if you trigger an error in a non-immediate context<br>
> with one of these objects active?<br>
<br>
</span>Like PerformPendingInstantiations?  My tool handles that itself<br>
using DiagnosticSuppressionScope as a primitive.  Basically I call<br>
PerformPendingInstantiations first to resolve any real errors in<br>
the original translation unit.  Then inside an instance of the<br>
proposed DiagnosticSuppressionScope I add one possible construct<br>
at a time and repeat PerformPendingInstantiations.<br>
<br>
My goal is to detect which implicit class member definitions can<br>
be safely called/compiled.  The tool works as follows:<br>
<br>
1. Use CI.getPreprocessor().enableIncrementalProcessing() to<br>
   keep the parser alive and prevent ActOnEndOfTranslationUnit.<br>
<br>
2. In HandleTranslationUnit, call PerformPendingInstantiations first.<br>
   Then use DiagnosticSuppressionScope and DiagnosticErrorTrap to<br>
   call methods like DefineImplicitDefaultConstructor one at a time.<br>
   Each time we call PerformPendingInstantiations inside the protected<br>
   scope and then check the trap to decide whether to mark the implicit<br>
   decl invalid with setInvalidDecl.<br>
<br>
3. In HandleTranslationUnit, after looping over all implicit members<br>
   of all classes as above, call ActOnEndOfTranslationUnit.  Then<br>
   perform visitation an ASTConsumer normally does.<br>
<br>
With this approach my ASTConsumer can visit all valid APIs that<br>
a program could call without error even if the translation unit<br>
does not spell out calls to all allowed implicit members.</blockquote><div><br></div><div>As noted above, this won't work in all cases. The problem is with a case like:</div><div><br></div><div>template<typename T> struct A {</div><div>  A() { T::error; }</div><div>};</div><div>struct B : A<int> {};</div><div>struct C : A<int> {};</div><div><br></div><div>Trying to create B::B() will trigger the instantiation of A<int>::A(), which will fail with a non-local error. We'll mark the function as invalid, and you'll determine that B::B() doesn't work. Then you'll try C::C(), which will *succeed*, because we'll silently skip A<int>::A() because we've already marked it invalid.</div></div></div></div>