jit: gcc diagnostics are jit errors
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 17 May 2016 19:28:47 +0000 (19:28 +0000)
committerDavid Malcolm <dmalcolm@gcc.gnu.org>
Tue, 17 May 2016 19:28:47 +0000 (19:28 +0000)
libgccjit performs numerous checks at the API boundary, but
if these succeed, it ignores errors and other diagnostics emitted
within the core of gcc, and treats the compile of a gcc_jit_context
as having succeeded.

This patch ensures that if any diagnostics are emitted, they
are visible from the libgccjit API, and that the the context is
flagged as having failed.

For now any kind of diagnostic is treated as a jit error,
so warnings and notes also count as errors.

gcc/jit/ChangeLog:
* dummy-frontend.c: Include diagnostic.h.
(jit_begin_diagnostic): New function.
(jit_end_diagnostic): New function.
(jit_langhook_init): Register jit_begin_diagnostic
and jit_end_diagnostic with the global_dc.
* jit-playback.c: Include diagnostic.h.
(gcc::jit::playback::context::add_diagnostic): New method.
* jit-playback.h (struct diagnostic_context): Add forward
declaration.
(gcc::jit::playback::context::add_diagnostic): New method.

gcc/testsuite/ChangeLog:
* jit.dg/test-error-array-bounds.c: New test case.

From-SVN: r236342

gcc/jit/ChangeLog
gcc/jit/dummy-frontend.c
gcc/jit/jit-playback.c
gcc/jit/jit-playback.h
gcc/testsuite/ChangeLog
gcc/testsuite/jit.dg/test-error-array-bounds.c [new file with mode: 0644]

index ae0a5539f39a73b78de3ac95bb58c0d6ac1637f1..f9320eccee0a195e23961eb2e62bd930e57ac3b3 100644 (file)
@@ -1,3 +1,16 @@
+2016-05-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * dummy-frontend.c: Include diagnostic.h.
+       (jit_begin_diagnostic): New function.
+       (jit_end_diagnostic): New function.
+       (jit_langhook_init): Register jit_begin_diagnostic
+       and jit_end_diagnostic with the global_dc.
+       * jit-playback.c: Include diagnostic.h.
+       (gcc::jit::playback::context::add_diagnostic): New method.
+       * jit-playback.h (struct diagnostic_context): Add forward
+       declaration.
+       (gcc::jit::playback::context::add_diagnostic): New method.
+
 2016-05-17  David Malcolm  <dmalcolm@redhat.com>
 
        * docs/topics/expressions.rst (Function calls): Document
index 7194ba68ac4a55c96bfa95659d8c8b6531127c63..26311536186fda5276157628341ac5c2cf75d0e8 100644 (file)
@@ -25,6 +25,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "debug.h"
 #include "langhooks.h"
 #include "langhooks-def.h"
+#include "diagnostic.h"
 
 
 #include <mpfr.h>
@@ -90,6 +91,35 @@ struct ggc_root_tab jit_root_tab[] =
     LAST_GGC_ROOT_TAB
   };
 
+/* JIT-specific implementation of diagnostic callbacks.  */
+
+/* Implementation of "begin_diagnostic".  */
+
+static void
+jit_begin_diagnostic (diagnostic_context */*context*/,
+                     diagnostic_info */*diagnostic*/)
+{
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
+
+  /* No-op (apart from logging); the real error-handling is done in the
+     "end_diagnostic" hook.  */
+}
+
+/* Implementation of "end_diagnostic".  */
+
+static void
+jit_end_diagnostic (diagnostic_context *context,
+                   diagnostic_info *diagnostic)
+{
+  gcc_assert (gcc::jit::active_playback_ctxt);
+  JIT_LOG_SCOPE (gcc::jit::active_playback_ctxt->get_logger ());
+
+  /* Delegate to the playback context (and thence to the
+     recording context).  */
+  gcc::jit::active_playback_ctxt->add_diagnostic (context, diagnostic);
+}
+
 /* Language hooks.  */
 
 static bool
@@ -105,6 +135,10 @@ jit_langhook_init (void)
       registered_root_tab = true;
     }
 
+  gcc_assert (global_dc);
+  global_dc->begin_diagnostic = jit_begin_diagnostic;
+  global_dc->end_diagnostic = jit_end_diagnostic;
+
   build_common_tree_nodes (false);
 
   /* I don't know why this has to be done explicitly.  */
index 579230d3f98593886be5da83552e0f332f22adae..156448d13d546028c6357973c503da660486ac7b 100644 (file)
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "context.h"
 #include "fold-const.h"
 #include "gcc.h"
+#include "diagnostic.h"
 
 #include <pthread.h>
 
@@ -2833,6 +2834,43 @@ add_error_va (location *loc, const char *fmt, va_list ap)
                                  fmt, ap);
 }
 
+/* Report a diagnostic up to the jit context as an error,
+   so that the compilation is treated as a failure.
+   For now, any kind of diagnostic is treated as an error by the jit
+   API.  */
+
+void
+playback::context::
+add_diagnostic (struct diagnostic_context *diag_context,
+               struct diagnostic_info *diagnostic)
+{
+  /* At this point the text has been formatted into the pretty-printer's
+     output buffer.  */
+  pretty_printer *pp = diag_context->printer;
+  const char *text = pp_formatted_text (pp);
+
+  /* Get location information (if any) from the diagnostic.
+     The recording::context::add_error[_va] methods require a
+     recording::location.  We can't lookup the playback::location
+     from the file/line/column since any playback location instances
+     may have been garbage-collected away by now, so instead we create
+     another recording::location directly.  */
+  location_t gcc_loc = diagnostic_location (diagnostic);
+  recording::location *rec_loc = NULL;
+  if (gcc_loc)
+    {
+      expanded_location exploc = expand_location (gcc_loc);
+      if (exploc.file)
+       rec_loc = m_recording_ctxt->new_location (exploc.file,
+                                                 exploc.line,
+                                                 exploc.column,
+                                                 false);
+    }
+
+  m_recording_ctxt->add_error (rec_loc, "%s", text);
+  pp_clear_output_area (pp);
+}
+
 /* Dealing with the linemap API.  */
 
 /* Construct a playback::location for a recording::location, if it
index 905747c14cb2043aa427e48db5734b75b96df603..8f7a43db1b02516ae4b0cd22185797bfa2a4c94a 100644 (file)
@@ -27,6 +27,9 @@ along with GCC; see the file COPYING3.  If not see
 
 #include "jit-recording.h"
 
+struct diagnostic_context;
+struct diagnostic_info;
+
 namespace gcc {
 
 namespace jit {
@@ -202,6 +205,10 @@ public:
   const char *
   get_first_error () const;
 
+  void
+  add_diagnostic (struct diagnostic_context *context,
+                 struct diagnostic_info *diagnostic);
+
   void
   set_tree_location (tree t, location *loc);
 
index 0e648e58ef09c941969f84218bac0576e80e0665..cb5940e2c904dad545be30e0c2b311e998490c6c 100644 (file)
@@ -1,3 +1,7 @@
+2016-05-17  David Malcolm  <dmalcolm@redhat.com>
+
+       * jit.dg/test-error-array-bounds.c: New test case.
+
 2016-05-17  Marc Glisse  <marc.glisse@inria.fr>
 
        * gcc.dg/tree-ssa/and-1.c: New testcase.
diff --git a/gcc/testsuite/jit.dg/test-error-array-bounds.c b/gcc/testsuite/jit.dg/test-error-array-bounds.c
new file mode 100644 (file)
index 0000000..732ec87
--- /dev/null
@@ -0,0 +1,72 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+       char
+       test_array_bounds (void)
+       {
+         char buffer[10];
+         return buffer[10];
+       }
+     with -Warray-bounds and -ftree-vrp and verify that the
+     out-of-bounds access is detected and reported as a jit error.  */
+  gcc_jit_context_add_command_line_option (ctxt, "-Warray-bounds");
+  gcc_jit_context_add_command_line_option (ctxt, "-ftree-vrp");
+
+  /* Ensure that the error message doesn't contain colorization codes,
+     even if run at a TTY.  */
+  gcc_jit_context_add_command_line_option (ctxt, "-fdiagnostics-color=never");
+
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *array_type =
+    gcc_jit_context_new_array_type (ctxt, NULL,
+                                   char_type, 10);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+  /* Build the test_fn.  */
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                 GCC_JIT_FUNCTION_EXPORTED,
+                                 char_type,
+                                 "test_array_bounds",
+                                 0, NULL,
+                                 0);
+  gcc_jit_lvalue *buffer =
+    gcc_jit_function_new_local (test_fn, NULL, array_type, "buffer");
+
+  /* tree-vrp.c:check_all_array_refs only checks array lookups that
+     have source locations.  */
+  gcc_jit_location *dummy_loc =
+    gcc_jit_context_new_location (ctxt, "dummy.c", 10, 4);
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+  gcc_jit_rvalue *index =
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 10);
+  gcc_jit_lvalue *read_of_the_buffer =
+    gcc_jit_context_new_array_access (ctxt, dummy_loc,
+                                     gcc_jit_lvalue_as_rvalue (buffer),
+                                     index);
+  gcc_jit_block_end_with_return (
+    block, dummy_loc,
+    gcc_jit_lvalue_as_rvalue (read_of_the_buffer));
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  /* Verify that the diagnostic led to the context failing... */
+  CHECK_VALUE (result, NULL);
+
+  /* ...and that the message was captured by the API.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+                     "array subscript is above array bounds [-Warray-bounds]");
+}