[cfe-dev] Trouble using TextDiagnosticPrinter

Billy O'Mahony via cfe-dev cfe-dev at lists.llvm.org
Wed Oct 14 12:17:13 PDT 2020


After much hacking I managed to write a DiagnosticConsumer that would emit
some error messages for me. Kudos to Andrzej for his help.

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.

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.

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.


class MyDiagnosticConsumer : public clang::DiagnosticConsumer {
    void HandleDiagnostic(clang::DiagnosticsEngine::Level DiagLevel, const
clang::Diagnostic& Info) override {
        llvm::SmallVector<char, 512> message;
        llvm::errs() << message << '\n';
         cout << "Hello HandleDiagnostic!" << endl;

class MyVisitor : public RecursiveASTVisitor<MyVisitor> {
  explicit MyVisitor(ASTContext *context)
    : mContext(context) {}

  bool VisitFunctionDecl(FunctionDecl* fnDecl) {
      // let's just issue an error on every function decl!

      auto& diagEngine = mContext->getDiagnostics();
      const auto ID =
                                                 "%0 declared? You
insensitive clod!");
      auto Builder = diagEngine.Report(fnDecl->getLocation(), ID);

      Builder.setForceEmit();  // <<< without this
MyDiagnosticConsumer::HandleDiagnostic is never called !!

      return true;

  ASTContext *mContext;

class MyConsumer : public clang::ASTConsumer {
  explicit MyConsumer(ASTContext *Context) : Visitor(Context) {

      DiagnosticsEngine &diagEngine = Context->getDiagnostics();

      // if I set my own DiagnosticsConsumer here it works (but no
line/file info).
      diagEngine.setClient(new MyDiagnosticConsumer(),

      ---- OR ----

      // if I set a TextDiagnosticPrinter it crashes later on
      // At the point where I otherwise get an error like
'.../include/bla.h' file not found.
      IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new
      TextDiagnosticPrinter *DiagClient =
          new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
      diagEngine.setClient(DiagClient, true); // true => shouldOwnClient

  virtual void HandleTranslationUnit(clang::ASTContext &Context) {
      auto Decls = Context.getTranslationUnitDecl()->decls();
      auto &SM = Context.getSourceManager();
      for (auto &Decl : Decls) {
          const auto& FileID = SM.getFileID(Decl->getLocation());
          if (FileID != SM.getMainFileID()) {
              // Skip decls coming via #incl


  MyVisitor Visitor;

Program received signal SIGSEGV, Segmentation fault.
clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
    FixItHints=..., D=...) at
95        beginDiagnostic(D, Level);
(gdb) bt
#0  clang::DiagnosticRenderer::emitDiagnostic (this=0x0, Loc=...,
Level=clang::DiagnosticsEngine::Fatal, Message=..., Ranges=...,
    FixItHints=..., D=...) at
#1  0x00000000084ce036 in clang::TextDiagnosticPrinter::HandleDiagnostic
(this=0x9b22430, Level=clang::DiagnosticsEngine::Fatal, Info=...)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20201014/23c71ceb/attachment.html>

More information about the cfe-dev mailing list