<div dir="ltr">David~<div><br></div><div>I really like this proposal.  I would greatly like a major improvement in matchers handling of Types as well.</div><div><br></div><div><a href="https://gcc.godbolt.org/z/w5jusg">https://gcc.godbolt.org/z/w5jusg</a><br></div><div><br></div><div>The only solution I could find involves peeling out of the typeloc space to ask about implicitness in the decl space.</div><div><br></div><div>declaratorDecl(unless(isImplicit()),<br>  hasTypeLoc(typeLoc(loc(qualType(elaboratedType(namesType( typedefType()))))).bind("loc"))<br>)<br><br>I know a slight shift from the current topic, but my original support for this change was based on my (false) belief that it also addressed implicit TypeLocs in a more principled fashion.</div><div><br></div><div>Matt</div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Mon, Jun 29, 2020 at 7:22 PM David Rector <<a href="mailto:davrecthreads@gmail.com">davrecthreads@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div style="overflow-wrap: break-word;"><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">Stephen you’ve raised a great point about how the user should be able to interface with Stmt nodes, and your clang-query idea is absolutely great, I love it.   </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">But I don’t think your proposed solution is broad enough, even for your own use case.  Below I give an easy, general solution that would work for you and everyone else.  (This clarifies & applies to Stephen’s case the points I discussed with Richard earlier.)  Please point out where you see a problem with this; that would at least help clarify the discussion for others.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">To summarize the issue, the now famous "B-42" example:</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">struct B { B(int); }</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">B func1() { return 42; }</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">This currently get matches for `hasReturnValue(exprWCleanups())`; you want it to match `hasReturnValue(integerLiteral())` under a new "beginner" setting.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">But if we’re going to introduce a new, easier setting, why not go all out, and let it *also* match `hasReturnValue(cxxConstructExpr())` OR hasReturnValue(materializeTemporaryExpr()) OR, yes, even the original `hasReturnValue(exprWithCleanups())`?  I believe this is what Richard originally suggested.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">We should call this setting "easy" mode — and I would probably agree with you that it *should* be made the default, for *everyone*’s sake, not just beginners - more on that later.  </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">This is how it could be implemented, three steps:</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">1. Add Expr::isImplicit(), Expr::desalt(), and Expr::getAs<T>(), the latter two similar but, as Richard pointed out, anti-analogous to Type::desugar() and Type::getAs<T>().  (I support introducing these in the main AST nodes, rather than only in ASTMatchers, so that other users of the AST can inteface with nodes in the same way ASTMatchers do, thereby avoiding a bifurcation in how AST nodes are interpreted and used.)</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap"> </span>class Expr : public Stmt {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                </span>//…</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">     </span>public:</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">           </span>bool isImplicit() const {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                 </span>//…Dispatch to the most derived type’s isImplicit(), and be sure they all define one.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">         </span>}</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">         </span>/// Whereas Type::desugar peels off meaningless syntax ("sugar") to get at underlying semantics, this</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">           </span>/// peels off invisible semantics ("salt") to get at underlying syntax.  (Proposed name, open to suggestions.)</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">         </span>Expr * desalt() const {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                   </span>if (!this->isImplicit())</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                               </span>return nullptr;</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                   </span>assert(children.end() = children.begin() + 1 &&</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                           </span>  "Expected implicit nodes to have exactly one child");</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                        </span>return *children.begin();</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">         </span>}</div><p style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><span style="white-space:pre-wrap">           </span><br></p><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">          </span>template<typename T></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                </span>T *getAs() const {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                        </span>if (isa<T>(this)) </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                         </span>return cast<T>(this);</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                       </span>return desalt()->getAs<T>();</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">             </span>}</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap"> </span>};</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">2. In the ASTMatchers implem, define BoundNodes::getNodeAs<T>() in terms of Stmt::getAs<T>().  I think it would be as simple as this:</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">  <span style="white-space:pre-wrap">   </span>class BoundNodes {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                </span>//… </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">    <span style="white-space:pre-wrap">             </span>template <typename T></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">    <span style="white-space:pre-wrap">         </span>const T *getNodeAs(StringRef ID) const {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                  </span>if (std::is_base_of<Expr, T>::value) {</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                              </span>if (Expr *E = MyBoundNodes.getNodeAs<Expr>(ID))</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                                     </span>return E->getAs<T>();</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                            </span>return nullptr;</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">                   </span>}</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">      <span style="white-space:pre-wrap">                        </span>return MyBoundNodes.getNodeAs<T>(ID);</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><span style="white-space:pre-wrap">               </span>}</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">    <span style="white-space:pre-wrap">   </span>};</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">```</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">At this point, if on the B-42 example you call</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">`returnStmt(hasReturnValue(expr().bind("theReturnVal")))`</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">when in "easy" mode, for theReturnVal you should be able to getNodeAs<IntegerLiteral>(), getNodeAs<ExprWCleanups>(), getNodeAs<CXXConstructExpr>() etc — all would be nonnull, users can take their pick.  And btw, if you wanted to get the other CXXConstructExpr, since there are two, you would call firstConstructExpr->desalt()->getAs<CXXConstructExpr>()).  And, if you only wanted matches that were non-implicit, you'd use ignoreImplicit as usual — but you would have to specify this.  This would force the user to reckon with the existence of what I guess I’m calling "semantic salt" over their syntax, without forcing them to manually dust it all off to get to a simple IntegerLiteral underneath.  </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">So the user retains maximum flexibility, but gains maximum tightness/expressiveness, in this new mode.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">3. The last part of the puzzle: how to allow `hasReturnValue(integerLiteral())` to match the "return 42;" in the B-42 example.  From perusing ASTMatchersInternal.h, it seems you would just want to change any dyn_cast<SomeExpr>(E) to E->getAs<T>() when in "easy" mode.  If a generic template is used somewhere, specialize it for Exprs to do this, same as we did for getNodeAs<T>().</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">Then, it should be able to work as you suggested — correct me if I’m wrong.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">What is more, as you suggested, this really isn’t just a beginner mode — the experts would benefit too:</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">Suppose in the future we find we need more than just ExprWCleanups — we need an extra implicit ExprWExtraCleanups that wraps the ExprWCleanups and everything else.  Or we need new inner implicit nodes.  If an expert used "easy" mode and getNodeAs<ExprWCleanups>(), and getAs<T>() whenever they sought to navigate to a child of an implicit node, he/she would not need to change her code at all.  Only if she required that each match was exact (call such a mode "directMatchOnly" perhaps) would she need to do a lot of maintenance whenever a new implicit node is introduced.  </div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">That’s why I would probably agree with Stephen that "easy" mode should probably be the default — the user should have to call "directMatchOnly" to opt out.  But I could see the other side of it too.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">Bottom line: you’ve raised a great but subtle point, doggedly pursued it, but now, let’s just get rid of the half measures — let’s go all out with a solution that is easy and lifts all boats.</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">If there is some problem this way of doing things won’t solve, please point it out — that would at least clarify the discussion for others who perhaps can help better than I can.  Thanks again for your efforts,</div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier;min-height:12px"><br></div><div style="margin:0px;font-stretch:normal;font-size:10px;line-height:normal;font-family:Courier">- Dave</div><div><br><blockquote type="cite"><div>On Jun 28, 2020, at 7:07 PM, Stephen Kelly via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>> wrote:</div><br><div>
  
    
  
  <div bgcolor="#FFFFFF"><p><br>
    </p>
    <div>On 24/06/2020 21:26, Yitzhak Mandelbaum
      wrote:<br>
    </div>
    <blockquote type="cite">
      
      <div dir="ltr">
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif">My 2cents: </div>
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
        </div>
      </div>
    </blockquote><p><br>
    </p><p>Thanks for responding about the matcher output from clang-query.<br>
    </p><p><br>
    </p>
    <blockquote type="cite">
      <div dir="ltr">
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif">I mostly agree
          with Richard and Sam. My only concern w/ Richard's proposal is
          that the hybrid model may be even more confusing to the
          beginner, since it may be harder to predict how a given
          matcher will match against an AST.  The system will be more
          forgiving, yet it becomes harder to build a mental model of
          how it works. <br>
        </div>
      </div>
    </blockquote><p><br>
    </p><p>In addition to making clang-query output relatable information, I
      agree with what you wrote here about creating a mental model.<br>
    </p><p><br>
    </p>
    <blockquote type="cite">
      <div dir="ltr">
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif"> I think we'd
          need to be sure we can concisely explain how this mode works,
          without having to reference any code/algorithms. For example,
          is there a deterministic elaboration from any unadorned
          matcher to a matcher with explicit `traverse` annotations?
          That would allow us to give some examples that illuminate
          what's happening. Otherwise, I'd prefer we just go back to the
          original default for the library. I'm fine if
          beginner-oriented tools want to start with "IgnoreUnless..."
          as their default. It sounds like Stephen is amenable to this
          approach as well from his last reply.</div>
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif"><br>
        </div>
      </div>
    </blockquote><p><br>
    </p><p>I think reversing the change of default is a worse outcome, but I
      think it's better than the current state of unhappiness from
      people. <br>
    </p><p>Further development can't happen until this thread is resolved I
      think.</p><p>However, if the default is changed back, I think there is less
      reason to add the matcher output feature to clang-query, because
      it will either need to <br>
    </p><p>* not show ignoring*() matchers in its output<br>
    </p><p>* show output based on each of (and none of) the ignoring*()
      matchers being applied</p><p>I think that would be too noisy and I don't think it's a good
      thing to require newcomer users to immediately create a mental
      model which requires those matchers.<br>
    </p><p><br>
    </p>
    <blockquote type="cite">
      <div dir="ltr">
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif">re:
          context-sensitive suggestions. </div>
        <div class="gmail_default" style="font-family:arial,helvetica,sans-serif">Stephen, if you
          drop the need to suggest all possible matchers at that point
          and only provide (beginner) helpful suggestions, does your
          concern go away?  </div>
      </div>
    </blockquote><p><br>
    </p><p>It doesn't change my concern. <br>
    </p><p>I don't know how you would determine what should be in the output
      and what shouldn't. Also, this content is not just for beginners.
      I use the feature still.</p><p>I don't think this is the thread for details such as your other
      question.</p><p><br>
    </p>
    <blockquote type="cite">
      <div dir="ltr"><span class="gmail_default" style="font-family:arial,helvetica,sans-serif">Overall, </span>I'm<span class="gmail_default" style="font-family:arial,helvetica,sans-serif"> </span>pessimistic
        ab<span class="gmail_default" style="font-family:arial,helvetica,sans-serif"></span>out
        making the current matchers easier for users.</div>
    </blockquote><p><br>
    </p><p>I think if AST Matchers are not going to be removed, we should
      make them easier for users.</p><p><br>
    </p>
    <blockquote type="cite">
      <div dir="ltr"> I think the AST is challenging for beginners and
        band aids will not solve that and can often make it worse. If we
        want beginner-friendly tooling (and I do!) we need to admit its
        cost and then invest in it.<span style="font-family:arial,helvetica,sans-serif"></span></div>
    </blockquote><p><br>
    </p><p>Yes, I have started such tooling, but there is much more that can
      be done.<br>
    </p><p>But, as in this thread, I don't think this is fully a tooling
      issue. It's also about discoverability and that means making it
      easier for users to create a mental model that doesn't require
      them to put ignoringImplicit() everywhere.</p><p><br>
    </p><p>Thanks Yitzhak for your input. I remain interested in
      feedback/input from others on the content I quote below.<br>
    </p><p><br>
    </p><p>Thanks,</p><p>Stephen.<br>
    </p><p><br>
    </p>
    <blockquote type="cite">
      <div class="gmail_quote">
        <div dir="ltr" class="gmail_attr">On Mon, Jun 22, 2020 at 5:51
          PM Stephen Kelly via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a>>
          wrote:<br>
        </div>
        <blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
          <div bgcolor="#FFFFFF"><br><p>The main reason I'm not supportive of this idea is that I
              want to make clang-query tell the user what matchers they
              can use with the nodes in the binding list.<br>
            </p><p>For example, if I write<br>
            </p><p> returnStmt()</p><p>in clang-query it should tell me that I can write <br>
            </p><p> hasReturnValue(integerLiteral())<br>
            </p><p>inside the expr():</p><p> <a href="http://ce.steveire.com/z/9EF8x0" target="_blank">http://ce.steveire.com/z/9EF8x0</a></p><p>That's how I as a newcomer quickly discover
              hasReturnValue() and integerLiteral().</p><p>You have no idea how overwhelming <br>
            </p><p> <a href="http://clang.llvm.org/docs/LibASTMatchersReference.html" target="_blank">http://clang.llvm.org/docs/LibASTMatchersReference.html</a><br>
            </p><p>is to someone who has zero familiarity with the clang
              AST.</p><p>But the above link is interactive and it aids *discovery*
              which is what my talk was about and which is what I'm
              trying to make easier with AST Matchers. The above
              suggested clang-query feature (not upstream yet) tells me
              at every step which matchers I can use in the context of
              what I am trying to achieve.<br>
            </p><p>However, if all of the implicit nodes should also appear
              in that output, and if in<br>
            </p><p>`returnStmt(hasReturnValue(expr().bind("theReturnVal")))`</p><p>the expr() should match the exprWithCleanups(), then I
              don't know how to make that feature work. If the expr() is
              the exprWithCleanups() then the tool definitely shouldn't
              tell the user they can write integerLiteral() there. The
              output for implicit nodes would add lots of noise and
              would have to be neutral in terms of what it recommends.<br>
            </p><p>The entire point of what I'm trying to do is not present
              the user with exprWithCleanups() and let them achieve
              their goals without it. I don't know if that's possible
              with the ideas floating around at the moment about making
              AST Matchers present all of the implicit nodes.</p><p>But, if making IgnoreUnlessSpelledInSource non-default
              means that I can continue work toward that goal (and eg
              ignore template instantiations and other implicit nodes
              which are not skipped yet), then maybe that's a viable way
              forward. So, that's my preference now I think.<br>
            </p><p>That way, people who want expert mode get it by default,
              and newcomers (and anyone else who doesn't want to write
              ignoringImplicit() everywhere) can relatively easily get
              the easier mode, and can use the expert mode when wanting
              to match implicit nodes. <br>
            </p><p>That might be the best compromise.<br>
            </p><p>Thanks,</p><p>Stephen<br>
            </p><p><br>
            </p>
          </div>
          _______________________________________________<br>
          cfe-dev mailing list<br>
          <a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br>
          <a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" rel="noreferrer" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br>
        </blockquote>
      </div>
    </blockquote>
  </div>

_______________________________________________<br>cfe-dev mailing list<br><a href="mailto:cfe-dev@lists.llvm.org" target="_blank">cfe-dev@lists.llvm.org</a><br><a href="https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev" target="_blank">https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev</a><br></div></blockquote></div><br></div></blockquote></div>