<div dir="ltr"><div>Hi Billy,</div><div><br></div><div>I've also run into this issue but I skirted around it by creating a <a href="https://clang.llvm.org/doxygen/classclang_1_1FixItRewriter.html">FixItRewriter</a> which is actually a DiagnosticConsumer which the diagnostics engine DOESN'T own. Unsure if this is the same case that you're running into, but when I was experiencing segfaults I found it to be an issue with lifetime management for diagnostic consumers. YMMV since the issue is within the FixItRewriter impl itself, but the class stores a pointer to the current diagnostic engine's client before setting the instance of FixItRewriter as our own. If we tell the engine to own the FixItRewriter, then the previous consumer is destroyed, and our FixItRewriter is then pointing to a destroyed resource. Can you try creating a std::unique_ptr for your own diagnostics consumer and tell the engine not to own it? You'd have to take care of the storage lifetime in this case.</div><div><br></div><div>Also, one more thing is, when the Builder object gets destroyed it performs an Emit(), and if you previously Emit then it won't do a double-write. At the closing curly brace of your VisitFunctionDecl, it may be a good idea to check which consumer you are currently using. I did a GDB backtrace in my situation at the end-curly-brace and found that the diagnostics consumer used to emit the message was actually not the one I thought I was using.</div><div><br></div><div>Since I didn't use the Visitor pattern but rather the Matcher pattern, my scope of how the two use cases differ are limited. Hope you find the bug!<br></div><div><br></div><div>Best,</div><div>Ray<br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Wed, Oct 14, 2020 at 12:17 PM Billy O'Mahony via cfe-dev <<a href="mailto:cfe-dev@lists.llvm.org">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 dir="ltr">Hi,<div><br></div><div>After much hacking I managed to write a DiagnosticConsumer that would emit some error messages for me. Kudos to Andrzej for his help.</div><div><br></div><div>I was expecting that I would more or less automatically get filename, line number and some source location carets added and some nice coloured text on my console. So for that I think I might need to use TextDiagnosticPrinter? However when I try to setClient that in my ASTContext's diagEngine it segfaults when a diagnostic is emitted.</div><div><br></div><div>I've tried looking in the clang/tools files for inspiration from other FrontendAction style tools but they either don't use TextDiagnosticPrinter or else they use some other clang infra like clang/Rewrite/Core/Rewriter.h.</div><div><br></div><div>This really feels like it should be super simple but I'm finding it very frustrating. My tool is actually doing useful things to spot project-specific code defects but now adding something simple like neat error messages is turning into a total quagmire.</div><div><br></div><div>Thanks,</div><div>Billy.</div><div><br></div><div>class MyDiagnosticConsumer : public clang::DiagnosticConsumer {<br>public:<br>    void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic& Info) override {<br>        llvm::SmallVector<char, 512> message;<br>        Info.FormatDiagnostic(message);<br>        llvm::errs() << message << '\n';<br>         cout << "Hello HandleDiagnostic!" << endl;<br>    }<br>};<br><br>class MyVisitor : public RecursiveASTVisitor<MyVisitor> {<br>public:<br>  explicit MyVisitor(ASTContext *context)<br>    : mContext(context) {}<br><br>  bool VisitFunctionDecl(FunctionDecl* fnDecl) {<br>      // let's just issue an error on every function decl!<br>      <br>      auto& diagEngine = mContext->getDiagnostics();<br>      const auto ID = diagEngine.getCustomDiagID(clang::DiagnosticsEngine::Error,<br>                                                 "%0 declared? You insensitive clod!");<br>      auto Builder = diagEngine.Report(fnDecl->getLocation(), ID);<br>      Builder.AddString(fnDecl->getNameAsString());<br>      Builder.AddSourceRange(clang::CharSourceRange::getCharRange(call->getSourceRange()));<br>      Builder.setForceEmit();  // <<< without this MyDiagnosticConsumer::HandleDiagnostic is never called !!<br><br>      return true;<br>  }<br><br>private:<br>  ASTContext *mContext;<br>};<br><br><br>class MyConsumer : public clang::ASTConsumer {<br>public:<br>  explicit MyConsumer(ASTContext *Context) : Visitor(Context) {<br>      <br>      DiagnosticsEngine &diagEngine = Context->getDiagnostics();<br>      <br>      // if I set my own DiagnosticsConsumer here it works (but no line/file info).<br>      diagEngine.setClient(new MyDiagnosticConsumer(), /*ShouldOwnClient=*/true);<br>      <br>      ---- OR ----<br>      <br>      // if I set a TextDiagnosticPrinter it crashes later on <br>      // At the point where I otherwise get an error like '.../include/bla.h' file not found.<br>      IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();<br>      TextDiagnosticPrinter *DiagClient =<br>          new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);<br>      diagEngine.setClient(DiagClient, true); // true => shouldOwnClient<br>  }<br><br>  virtual void HandleTranslationUnit(clang::ASTContext &Context) {<br>      auto Decls = Context.getTranslationUnitDecl()->decls();<br>      auto &SM = Context.getSourceManager();<br>      for (auto &Decl : Decls) {<br>          const auto& FileID = SM.getFileID(Decl->getLocation());<br>          if (FileID != SM.getMainFileID()) {<br>              // Skip decls coming via #incl<br>              continue;<br>          }<br><br>          Visitor.TraverseDecl(Decl);<br>      }<br>  }<br><br>private:<br>  MyVisitor Visitor;<br>};<br><br><br><br><br>Program received signal SIGSEGV, Segmentation fault.<br>clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=..., Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,<br>    FixItHints=..., D=...) at /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95<br>95        beginDiagnostic(D, Level);<br>(gdb) bt<br>#0  clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=..., Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,<br>    FixItHints=..., D=...) at /home/bomahony/llvm/tools/clang/lib/Frontend/DiagnosticRenderer.cpp:95<br>#1  0x00000000084ce036 in clang::TextDiagnosticPrinter::HandleDiagnostic (this=0x9b22430, Level=clang::DiagnosticsEngine::Fatal, Info=...)<br>    at /home/bomahony/llvm/tools/clang/lib/Frontend/TextDiagnosticPrinter.cpp:152<br>    <br>    <br></div></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>