[PATCH] Add DiagnosticSuppressionScope RAII class

Richard Smith richard at metafoo.co.uk
Tue Oct 28 14:46:33 PDT 2014


On Tue, Oct 28, 2014 at 10:56 AM, Brad King <brad.king at kitware.com> wrote:

> On 10/28/2014 01:35 PM, Richard Smith wrote:
> > How does this compare to Sema's existing SFINAETrap mechanism?
>
> It is more general than SFINAETrap.
>
> I originally tried that but it is insufficient.  Inside any template
> instantiation Sema::InstantiatingTemplate::Initialize always sets
> InNonInstantiationSFINAEContext to false so Sema::isSFINAEContext
> returns None and SFINAETrap does not suppress the error.


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).

Also I
> want to suppress all errors, not just those tolerated by SFINAE.
>
> > What happens if you trigger an error in a non-immediate context
> > with one of these objects active?
>
> Like PerformPendingInstantiations?  My tool handles that itself
> using DiagnosticSuppressionScope as a primitive.  Basically I call
> PerformPendingInstantiations first to resolve any real errors in
> the original translation unit.  Then inside an instance of the
> proposed DiagnosticSuppressionScope I add one possible construct
> at a time and repeat PerformPendingInstantiations.
>
> My goal is to detect which implicit class member definitions can
> be safely called/compiled.  The tool works as follows:
>
> 1. Use CI.getPreprocessor().enableIncrementalProcessing() to
>    keep the parser alive and prevent ActOnEndOfTranslationUnit.
>
> 2. In HandleTranslationUnit, call PerformPendingInstantiations first.
>    Then use DiagnosticSuppressionScope and DiagnosticErrorTrap to
>    call methods like DefineImplicitDefaultConstructor one at a time.
>    Each time we call PerformPendingInstantiations inside the protected
>    scope and then check the trap to decide whether to mark the implicit
>    decl invalid with setInvalidDecl.
>
> 3. In HandleTranslationUnit, after looping over all implicit members
>    of all classes as above, call ActOnEndOfTranslationUnit.  Then
>    perform visitation an ASTConsumer normally does.
>
> With this approach my ASTConsumer can visit all valid APIs that
> a program could call without error even if the translation unit
> does not spell out calls to all allowed implicit members.


As noted above, this won't work in all cases. The problem is with a case
like:

template<typename T> struct A {
  A() { T::error; }
};
struct B : A<int> {};
struct C : A<int> {};

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.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20141028/0a8a4c0a/attachment.html>


More information about the cfe-commits mailing list