[llvm-c] Expose LLVMContextGetDiagnostic{Handler,Context}

Differential Revision: http://reviews.llvm.org/D18820

llvm-svn: 265773
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index a339ce9..d9b6712 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -432,6 +432,16 @@
                                      void *DiagnosticContext);
 
 /**
+ * Get the diagnostic handler of this context.
+ */
+LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C);
+
+/**
+ * Get the diagnostic context of this context.
+ */
+void *LLVMContextGetDiagnosticContext(LLVMContextRef C);
+
+/**
  * Set the yield callback function for this context.
  *
  * @see LLVMContext::setYieldCallback()
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 93a346b..1b4ad20 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -85,10 +85,20 @@
                                      LLVMDiagnosticHandler Handler,
                                      void *DiagnosticContext) {
   unwrap(C)->setDiagnosticHandler(
-      LLVM_EXTENSION reinterpret_cast<LLVMContext::DiagnosticHandlerTy>(Handler),
+      LLVM_EXTENSION reinterpret_cast<LLVMContext::DiagnosticHandlerTy>(
+          Handler),
       DiagnosticContext);
 }
 
+LLVMDiagnosticHandler LLVMContextGetDiagnosticHandler(LLVMContextRef C) {
+  return LLVM_EXTENSION reinterpret_cast<LLVMDiagnosticHandler>(
+      unwrap(C)->getDiagnosticHandler());
+}
+
+void *LLVMContextGetDiagnosticContext(LLVMContextRef C) {
+  return unwrap(C)->getDiagnosticContext();
+}
+
 void LLVMContextSetYieldCallback(LLVMContextRef C, LLVMYieldCallback Callback,
                                  void *OpaqueHandle) {
   auto YieldCallback =
diff --git a/llvm/test/Bindings/llvm-c/empty.ll b/llvm/test/Bindings/llvm-c/empty.ll
index eb73b83..84eb9fd 100644
--- a/llvm/test/Bindings/llvm-c/empty.ll
+++ b/llvm/test/Bindings/llvm-c/empty.ll
@@ -1,3 +1,5 @@
 ; RUN: llvm-as < %s | llvm-dis > %t.orig
 ; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo
 ; RUN: diff -w %t.orig %t.echo
+; RUN: llvm-as < %s | llvm-c-test --test-diagnostic-handler 2>&1 | FileCheck %s
+; CHECK: Diagnostic handler was not called while loading module
diff --git a/llvm/test/Bindings/llvm-c/invalid-bitcode.test b/llvm/test/Bindings/llvm-c/invalid-bitcode.test
index afae0ea..262cb88 100644
--- a/llvm/test/Bindings/llvm-c/invalid-bitcode.test
+++ b/llvm/test/Bindings/llvm-c/invalid-bitcode.test
@@ -8,3 +8,9 @@
 ; RUN: not llvm-c-test --lazy-new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s
 
 NEW: Error with new bitcode parser: Unknown attribute kind (52)
+
+; RUN: llvm-c-test --test-diagnostic-handler < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=DIAGNOSTIC %s
+
+DIAGNOSTIC: Executing diagnostic handler
+DIAGNOSTIC: Diagnostic severity is of type error
+DIAGNOSTIC: Diagnostic handler was called while loading module
diff --git a/llvm/tools/llvm-c-test/CMakeLists.txt b/llvm/tools/llvm-c-test/CMakeLists.txt
index 991e853..858f2b0 100644
--- a/llvm/tools/llvm-c-test/CMakeLists.txt
+++ b/llvm/tools/llvm-c-test/CMakeLists.txt
@@ -37,6 +37,7 @@
 
 add_llvm_tool(llvm-c-test
   calc.c
+  diagnostic.c
   disassemble.c
   echo.cpp
   helpers.c
diff --git a/llvm/tools/llvm-c-test/diagnostic.c b/llvm/tools/llvm-c-test/diagnostic.c
new file mode 100644
index 0000000..16d51747
--- /dev/null
+++ b/llvm/tools/llvm-c-test/diagnostic.c
@@ -0,0 +1,89 @@
+//===-- diagnostic.cpp - tool for testing libLLVM and llvm-c API ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the --test-diagnostic-handler command in llvm-c-test.
+//
+// This command uses the C API to read a module with a custom diagnostic
+// handler set to test the diagnostic handler functionality.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm-c-test.h"
+#include "llvm-c/BitReader.h"
+#include "llvm-c/Core.h"
+
+#include <stdio.h>
+
+static void diagnosticHandler(LLVMDiagnosticInfoRef DI, void *C) {
+  fprintf(stderr, "Executing diagnostic handler\n");
+
+  fprintf(stderr, "Diagnostic severity is of type ");
+  switch (LLVMGetDiagInfoSeverity(DI)) {
+  case LLVMDSError:
+    fprintf(stderr, "error");
+    break;
+  case LLVMDSWarning:
+    fprintf(stderr, "warning");
+    break;
+  case LLVMDSRemark:
+    fprintf(stderr, "remark");
+    break;
+  case LLVMDSNote:
+    fprintf(stderr, "note");
+    break;
+  }
+  fprintf(stderr, "\n");
+
+  (*(int *)C) = 1;
+}
+
+static int handlerCalled = 0;
+
+int llvm_test_diagnostic_handler(void) {
+  LLVMContextRef C = LLVMGetGlobalContext();
+  LLVMContextSetDiagnosticHandler(C, diagnosticHandler, &handlerCalled);
+
+  if (LLVMContextGetDiagnosticHandler(C) != diagnosticHandler) {
+    fprintf(stderr, "LLVMContext{Set,Get}DiagnosticHandler failed\n");
+    return 1;
+  }
+
+  int *DC = (int *)LLVMContextGetDiagnosticContext(C);
+  if (DC != &handlerCalled || *DC) {
+    fprintf(stderr, "LLVMContextGetDiagnosticContext failed\n");
+    return 1;
+  }
+
+  LLVMMemoryBufferRef MB;
+  char *msg = NULL;
+  if (LLVMCreateMemoryBufferWithSTDIN(&MB, &msg)) {
+    fprintf(stderr, "Error reading file: %s\n", msg);
+    LLVMDisposeMessage(msg);
+    return 1;
+  }
+
+
+  LLVMModuleRef M;
+  int Ret = LLVMGetBitcodeModule2(MB, &M);
+  if (Ret) {
+    // We do not return if the bitcode was invalid, as we want to test whether
+    // the diagnostic handler was executed.
+    fprintf(stderr, "Error parsing bitcode: %s\n", msg);
+  }
+
+  LLVMDisposeMemoryBuffer(MB);
+
+  if (handlerCalled) {
+    fprintf(stderr, "Diagnostic handler was called while loading module\n");
+  } else {
+    fprintf(stderr, "Diagnostic handler was not called while loading module\n");
+  }
+
+  return 0;
+}
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index e11fb7c..2c2a6da 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -7,7 +7,7 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// This file implements the --echo commands in llvm-c-test.
+// This file implements the --echo command in llvm-c-test.
 //
 // This command uses the C API to read a module and output an exact copy of it
 // as output. It is used to check that the resulting module matches the input
diff --git a/llvm/tools/llvm-c-test/llvm-c-test.h b/llvm/tools/llvm-c-test/llvm-c-test.h
index 60edc0d..0d1ade0 100644
--- a/llvm/tools/llvm-c-test/llvm-c-test.h
+++ b/llvm/tools/llvm-c-test/llvm-c-test.h
@@ -49,6 +49,9 @@
 // echo.c
 int llvm_echo(void);
 
+// diagnostic.c
+int llvm_test_diagnostic_handler(void);
+
 #ifdef __cplusplus
 }
 #endif /* !defined(__cplusplus) */
diff --git a/llvm/tools/llvm-c-test/main.c b/llvm/tools/llvm-c-test/main.c
index ec09467..90d3501 100644
--- a/llvm/tools/llvm-c-test/main.c
+++ b/llvm/tools/llvm-c-test/main.c
@@ -21,20 +21,20 @@
   fprintf(stderr, "llvm-c-test command\n\n");
   fprintf(stderr, " Commands:\n");
   fprintf(stderr, "  * --module-dump\n");
-  fprintf(stderr, "    Read bytecode from stdin - print disassembly\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --lazy-module-dump\n");
   fprintf(stderr,
-          "    Lazily read bytecode from stdin - print disassembly\n\n");
+          "    Lazily read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --new-module-dump\n");
-  fprintf(stderr, "    Read bytecode from stdin - print disassembly\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --lazy-new-module-dump\n");
   fprintf(stderr,
-          "    Lazily read bytecode from stdin - print disassembly\n\n");
+          "    Lazily read bitcode from stdin - print disassembly\n\n");
   fprintf(stderr, "  * --module-list-functions\n");
   fprintf(stderr,
-          "    Read bytecode from stdin - list summary of functions\n\n");
+          "    Read bitcode from stdin - list summary of functions\n\n");
   fprintf(stderr, "  * --module-list-globals\n");
-  fprintf(stderr, "    Read bytecode from stdin - list summary of globals\n\n");
+  fprintf(stderr, "    Read bitcode from stdin - list summary of globals\n\n");
   fprintf(stderr, "  * --targets-list\n");
   fprintf(stderr, "    List available targets\n\n");
   fprintf(stderr, "  * --object-list-sections\n");
@@ -46,12 +46,15 @@
   fprintf(stderr, "    Read lines of triple, hex ascii machine code from stdin "
                   "- print disassembly\n\n");
   fprintf(stderr, "  * --calc\n");
-  fprintf(stderr, "  * --echo\n");
-  fprintf(stderr,
-          "    Read object file form stdin - and print it back out\n\n");
   fprintf(
       stderr,
       "    Read lines of name, rpn from stdin - print generated module\n\n");
+  fprintf(stderr, "  * --echo\n");
+  fprintf(stderr,
+          "    Read bitcode file form stdin - print it back out\n\n");
+  fprintf(stderr, "  * --test-diagnostic-handler\n");
+  fprintf(stderr,
+          "    Read bitcode file form stdin with a diagnostic handler set\n\n");
 }
 
 int main(int argc, char **argv) {
@@ -87,6 +90,8 @@
     return llvm_set_metadata();
   } else if (argc == 2 && !strcmp(argv[1], "--echo")) {
     return llvm_echo();
+  } else if (argc == 2 && !strcmp(argv[1], "--test-diagnostic-handler")) {
+    return llvm_test_diagnostic_handler();
   } else {
     print_usage();
   }