diff mbox

[jit] Tighten up the distinction between pointers and arrays

Message ID 1395248564-11235-1-git-send-email-dmalcolm@redhat.com
State New
Headers show

Commit Message

David Malcolm March 19, 2014, 5:02 p.m. UTC
Committed to branch dmalcolm/jit:

https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
showed a problem where a parameter expecting a (char *) was passed
a char[1024] cast to a (char *) as its argument, leading to an ICE:

libgccjit.so: internal compiler error: in convert_move, at expr.c:320
0x7fffebea98ad convert_move(rtx_def*, rtx_def*, int)
	../../src/gcc/expr.c:320
0x7fffebec31cb expand_expr_real_2(separate_ops*, rtx_def*, machine_mode, expand_modifier)
	../../src/gcc/expr.c:8105
0x7fffec88d768 expand_gimple_stmt_1
	../../src/gcc/cfgexpand.c:2321
0x7fffec88d9cc expand_gimple_stmt
	../../src/gcc/cfgexpand.c:2381

The issue was that the recording::type::dereference method is used for
both pointers and for arrays, leading to sloppiness about where lvalues
and rvalues can be pointers vs arrays.

This commit introduces is_pointer and is_array methods, using them to
tighten up type-checking, converting the above ICE into an type-check
error when the cast is attempted:
  libgccjit.so: error: gcc_jit_context_new_cast: cannot cast buffer from type: char[1024] to type: char *

The correct way to use an array as a pointer in the JIT API is to use
   gcc_jit_lvalue_get_address
on the array, which gives you an rvalue representing the address of the
initial element, and then to cast that rvalue as necessary.

gcc/jit
	* internal-api.c (gcc::jit::recording::memento_of_get_pointer::
	accepts_writes_from): Accept writes from pointers, but not arrays.

	* internal-api.h (gcc::jit::recording::type::is_pointer): New.
	(gcc::jit::recording::type::is_array): New.
	(gcc::jit::recording::memento_of_get_type::accepts_writes_from):
	Allow (void *) to accept writes of pointers, but not arrays.
	(gcc::jit::recording::memento_of_get_type::is_pointer): New.
	(gcc::jit::recording::memento_of_get_type::is_array): New.
	(gcc::jit::recording::memento_of_get_pointer::is_pointer): New.
	(gcc::jit::recording::memento_of_get_pointer::is_array): New.
	(gcc::jit::recording::memento_of_get_const::is_pointer): New.
	(gcc::jit::recording::memento_of_get_const::is_array): New.
	(gcc::jit::recording::memento_of_get_volatile::is_pointer): New.
	(gcc::jit::recording::memento_of_get_volatile::is_array): New.
	(gcc::jit::recording::array_type::is_pointer): New.
	(gcc::jit::recording::array_type::is_array): New.
	(gcc::jit::recording::function_type::is_pointer): New.
	(gcc::jit::recording::function_type::is_array): New.
	(gcc::jit::recording::struct_::is_pointer): New.
	(gcc::jit::recording::struct_::is_array): New.

	* libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Require the
	pointer_type to be a pointer, not an array.
	(gcc_jit_context_null): Likewise.
	(is_valid_cast): Require pointer casts to be between pointer types,
	not arrays.
	(gcc_jit_context_new_array_access): Update error message from "not
	a pointer" to "not a pointer or array".
	(gcc_jit_rvalue_dereference_field): Require the pointer arg to be
	of pointer type, not an array.
	(gcc_jit_rvalue_dereference): Likewise.

gcc/testsuite/
	* jit.dg/test-array-as-pointer.c: New test case, verifying that
	there's a way to treat arrays as pointers.
	* jit.dg/test-combination.c: Add test-array-as-pointer.c...
	(create_code): ...here and...
	(verify_code): ...here.

	* jit.dg/test-error-array-as-pointer.c: New test case, verifying
	that bogus casts from array to pointer are caught by the type
	system, rather than leading to ICEs seen in:
	https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
---
 gcc/jit/ChangeLog.jit                              |  35 +++++++
 gcc/jit/internal-api.c                             |   2 +-
 gcc/jit/internal-api.h                             |  18 +++-
 gcc/jit/libgccjit.c                                |  14 +--
 gcc/testsuite/ChangeLog.jit                        |  13 +++
 gcc/testsuite/jit.dg/test-array-as-pointer.c       | 101 +++++++++++++++++++++
 gcc/testsuite/jit.dg/test-combination.c            |   9 ++
 gcc/testsuite/jit.dg/test-error-array-as-pointer.c |  99 ++++++++++++++++++++
 8 files changed, 282 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/jit.dg/test-array-as-pointer.c
 create mode 100644 gcc/testsuite/jit.dg/test-error-array-as-pointer.c
diff mbox

Patch

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 8244eba..efb1931 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,3 +1,38 @@ 
+2014-03-19  David Malcolm  <dmalcolm@redhat.com>
+
+	* internal-api.c (gcc::jit::recording::memento_of_get_pointer::
+	accepts_writes_from): Accept writes from pointers, but not arrays.
+
+	* internal-api.h (gcc::jit::recording::type::is_pointer): New.
+	(gcc::jit::recording::type::is_array): New.
+	(gcc::jit::recording::memento_of_get_type::accepts_writes_from):
+	Allow (void *) to accept writes of pointers, but not arrays.
+	(gcc::jit::recording::memento_of_get_type::is_pointer): New.
+	(gcc::jit::recording::memento_of_get_type::is_array): New.
+	(gcc::jit::recording::memento_of_get_pointer::is_pointer): New.
+	(gcc::jit::recording::memento_of_get_pointer::is_array): New.
+	(gcc::jit::recording::memento_of_get_const::is_pointer): New.
+	(gcc::jit::recording::memento_of_get_const::is_array): New.
+	(gcc::jit::recording::memento_of_get_volatile::is_pointer): New.
+	(gcc::jit::recording::memento_of_get_volatile::is_array): New.
+	(gcc::jit::recording::array_type::is_pointer): New.
+	(gcc::jit::recording::array_type::is_array): New.
+	(gcc::jit::recording::function_type::is_pointer): New.
+	(gcc::jit::recording::function_type::is_array): New.
+	(gcc::jit::recording::struct_::is_pointer): New.
+	(gcc::jit::recording::struct_::is_array): New.
+
+	* libgccjit.c (gcc_jit_context_new_rvalue_from_ptr): Require the
+	pointer_type to be a pointer, not an array.
+	(gcc_jit_context_null): Likewise.
+	(is_valid_cast): Require pointer casts to be between pointer types,
+	not arrays.
+	(gcc_jit_context_new_array_access): Update error message from "not
+	a pointer" to "not a pointer or array".
+	(gcc_jit_rvalue_dereference_field): Require the pointer arg to be
+	of pointer type, not an array.
+	(gcc_jit_rvalue_dereference): Likewise.
+
 2014-03-14  David Malcolm  <dmalcolm@redhat.com>
 
 	* libgccjit.c (is_valid_cast): Permit casts between pointer types.
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index 8e0395d..e3ddc4d 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -1048,7 +1048,7 @@  bool
 recording::memento_of_get_pointer::accepts_writes_from (type *rtype)
 {
   /* Must be a pointer type: */
-  type *rtype_points_to = rtype->dereference ();
+  type *rtype_points_to = rtype->is_pointer ();
   if (!rtype_points_to)
     return false;
 
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 772f828..34c1de3 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -496,6 +496,8 @@  public:
   virtual bool is_int () const = 0;
   virtual bool is_float () const = 0;
   virtual bool is_bool () const = 0;
+  virtual type *is_pointer () = 0;
+  virtual type *is_array () = 0;
 
   playback::type *
   playback_type ()
@@ -527,7 +529,7 @@  public:
   bool accepts_writes_from (type *rtype)
   {
     if (m_kind == GCC_JIT_TYPE_VOID_PTR)
-      if (rtype->dereference ())
+      if (rtype->is_pointer ())
 	{
 	  /* LHS (this) is type (void *), and the RHS is a pointer:
 	     accept it:  */
@@ -540,6 +542,8 @@  public:
   bool is_int () const;
   bool is_float () const;
   bool is_bool () const;
+  type *is_pointer () { return dereference (); }
+  type *is_array () { return NULL; }
 
 public:
   void replay_into (replayer *r);
@@ -568,6 +572,8 @@  public:
   bool is_int () const { return false; }
   bool is_float () const { return false; }
   bool is_bool () const { return false; }
+  type *is_pointer () { return m_other_type; }
+  type *is_array () { return NULL; }
 
 private:
   string * make_debug_string ();
@@ -598,6 +604,8 @@  public:
   bool is_int () const { return m_other_type->is_int (); }
   bool is_float () const { return m_other_type->is_float (); }
   bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
 
   void replay_into (replayer *);
 
@@ -624,6 +632,8 @@  public:
   bool is_int () const { return m_other_type->is_int (); }
   bool is_float () const { return m_other_type->is_float (); }
   bool is_bool () const { return m_other_type->is_bool (); }
+  type *is_pointer () { return m_other_type->is_pointer (); }
+  type *is_array () { return m_other_type->is_array (); }
 
   void replay_into (replayer *);
 
@@ -652,6 +662,8 @@  class array_type : public type
   bool is_int () const { return false; }
   bool is_float () const { return false; }
   bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return m_element_type; }
 
   void replay_into (replayer *);
 
@@ -679,6 +691,8 @@  public:
   bool is_int () const { return false; }
   bool is_float () const { return false; }
   bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
 
   void replay_into (replayer *);
 
@@ -756,6 +770,8 @@  public:
   bool is_int () const { return false; }
   bool is_float () const { return false; }
   bool is_bool () const { return false; }
+  type *is_pointer () { return NULL; }
+  type *is_array () { return NULL; }
 
   void replay_into (replayer *r);
 
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 5acb1bc..c9805de 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -721,7 +721,7 @@  gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context *ctxt,
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
   RETURN_NULL_IF_FAIL_PRINTF1 (
-    pointer_type->dereference (),
+    pointer_type->is_pointer (),
     ctxt, NULL,
     "not a pointer type (type: %s)",
     pointer_type->get_debug_string ());
@@ -736,7 +736,7 @@  gcc_jit_context_null (gcc_jit_context *ctxt,
   RETURN_NULL_IF_FAIL (ctxt, NULL, NULL, "NULL context");
   RETURN_NULL_IF_FAIL (pointer_type, ctxt, NULL, "NULL type");
   RETURN_NULL_IF_FAIL_PRINTF1 (
-    pointer_type->dereference (),
+    pointer_type->is_pointer (),
     ctxt, NULL,
     "not a pointer type (type: %s)",
     pointer_type->get_debug_string ());
@@ -906,8 +906,8 @@  is_valid_cast (gcc::jit::recording::type *src_type,
       return true;
 
   /* Permit casts between pointer types.  */
-  gcc::jit::recording::type *deref_src_type = src_type->dereference ();
-  gcc::jit::recording::type *deref_dst_type = dst_type->dereference ();
+  gcc::jit::recording::type *deref_src_type = src_type->is_pointer ();
+  gcc::jit::recording::type *deref_dst_type = dst_type->is_pointer ();
   if (deref_src_type && deref_dst_type)
     return true;
 
@@ -946,7 +946,7 @@  gcc_jit_context_new_array_access (gcc_jit_context *ctxt,
   RETURN_NULL_IF_FAIL_PRINTF2 (
     ptr->get_type ()->dereference (),
     ctxt, loc,
-    "%s (type: %s) is not a pointer",
+    "%s (type: %s) is not a pointer or array",
     ptr->get_debug_string (),
     ptr->get_type ()->get_debug_string ());
 
@@ -1007,7 +1007,7 @@  gcc_jit_rvalue_dereference_field (gcc_jit_rvalue *ptr,
   RETURN_NULL_IF_FAIL (ptr, NULL, loc, "NULL ptr");
   RETURN_NULL_IF_FAIL (field, NULL, loc, "NULL field");
   gcc::jit::recording::type *underlying_type =
-    ptr->get_type ()->dereference ();
+    ptr->get_type ()->is_pointer ();
   RETURN_NULL_IF_FAIL_PRINTF1 (field->get_container (), field->m_ctxt, loc,
 			       "field %s has not been placed in a struct",
 			       field->get_debug_string ());
@@ -1036,7 +1036,7 @@  gcc_jit_rvalue_dereference (gcc_jit_rvalue *rvalue,
   RETURN_NULL_IF_FAIL (rvalue, NULL, loc, "NULL rvalue");
 
   gcc::jit::recording::type *underlying_type =
-    rvalue->get_type ()->dereference ();
+    rvalue->get_type ()->is_pointer ();
 
   RETURN_NULL_IF_FAIL_PRINTF2 (
     underlying_type,
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index e07ba87..393bd8f 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,16 @@ 
+2014-03-19  David Malcolm  <dmalcolm@redhat.com>
+
+	* jit.dg/test-array-as-pointer.c: New test case, verifying that
+	there's a way to treat arrays as pointers.
+	* jit.dg/test-combination.c: Add test-array-as-pointer.c...
+	(create_code): ...here and...
+	(verify_code): ...here.
+
+	* jit.dg/test-error-array-as-pointer.c: New test case, verifying
+	that bogus casts from array to pointer are caught by the type
+	system, rather than leading to ICEs seen in:
+	https://github.com/davidmalcolm/pygccjit/pull/3#issuecomment-37883129
+
 2014-03-18  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
diff --git a/gcc/testsuite/jit.dg/test-array-as-pointer.c b/gcc/testsuite/jit.dg/test-array-as-pointer.c
new file mode 100644
index 0000000..1a240ac
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-array-as-pointer.c
@@ -0,0 +1,101 @@ 
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+        void test_of_array_as_pointer (const char *name)
+        {
+            snprintf (test_buffer, sizeof (test_buffer),
+	              "hello %s", name);
+        }
+    */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *char_ptr_type =
+    gcc_jit_type_get_pointer (char_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *size_t_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *buf_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+  /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+  gcc_jit_param *param_s =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+  gcc_jit_function *snprintf =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  int_type,
+				  "snprintf",
+				  3, snprintf_params,
+				  1);
+
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  void_type,
+				  "test_of_array_as_pointer",
+				  1, &param_name,
+				  0);
+
+  gcc_jit_lvalue *buffer =
+    gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+  gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+  /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+  gcc_jit_rvalue *args[4];
+  args[0] = gcc_jit_context_new_cast (
+    ctxt, NULL,
+    /* Here's the difference with test-error-array-as-pointer.c: */
+    gcc_jit_lvalue_get_address (buffer,
+				NULL),
+    char_ptr_type);
+  args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+						 size_t_type,
+						 BUFFER_SIZE);
+  args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+  args[3] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_NON_NULL (result);
+
+  typedef void (*fn_type) (const char *);
+  fn_type test_of_array_as_pointer =
+    (fn_type)gcc_jit_result_get_code (result, "test_of_array_as_pointer");
+  CHECK_NON_NULL (test_of_array_as_pointer);
+
+  test_of_array_as_pointer ("world");
+  CHECK_STRING_VALUE (test_buffer, "hello world");
+}
diff --git a/gcc/testsuite/jit.dg/test-combination.c b/gcc/testsuite/jit.dg/test-combination.c
index 72b8602..6f65592 100644
--- a/gcc/testsuite/jit.dg/test-combination.c
+++ b/gcc/testsuite/jit.dg/test-combination.c
@@ -14,6 +14,13 @@ 
 #undef create_code
 #undef verify_code
 
+/* test-array-as-pointer.c */
+#define create_code create_code_array_as_pointer
+#define verify_code verify_code_array_as_pointer
+#include "test-array-as-pointer.c"
+#undef create_code
+#undef verify_code
+
 /* test-arrays.c */
 #define create_code create_code_arrays
 #define verify_code verify_code_arrays
@@ -141,6 +148,7 @@  void
 create_code (gcc_jit_context *ctxt, void * user_data)
 {
   create_code_accessing_struct (ctxt, user_data);
+  create_code_array_as_pointer (ctxt, user_data);
   create_code_arrays (ctxt, user_data);
   create_code_calling_external_function (ctxt, user_data);
   create_code_dot_product (ctxt, user_data);
@@ -161,6 +169,7 @@  void
 verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
 {
   verify_code_accessing_struct (ctxt, result);
+  verify_code_array_as_pointer (ctxt, result);
   verify_code_arrays (ctxt, result);
   verify_code_calling_external_function (ctxt, result);
   verify_code_dot_product (ctxt, result);
diff --git a/gcc/testsuite/jit.dg/test-error-array-as-pointer.c b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c
new file mode 100644
index 0000000..cd2b7f8
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-array-as-pointer.c
@@ -0,0 +1,99 @@ 
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#define BUFFER_SIZE (1024)
+
+char test_buffer[1024];
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  /* Let's try to inject the equivalent of:
+        void test_of_array_as_pointer (const char *name)
+        {
+            snprintf (test_buffer, sizeof (test_buffer),
+	              "hello %s", name);
+        }
+    */
+  gcc_jit_type *void_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+  gcc_jit_type *const_char_ptr_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CONST_CHAR_PTR);
+  gcc_jit_type *char_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_CHAR);
+  gcc_jit_type *char_ptr_type =
+    gcc_jit_type_get_pointer (char_type);
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_type *size_t_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_SIZE_T);
+  gcc_jit_type *buf_type =
+    gcc_jit_context_new_array_type (ctxt, NULL, char_type, BUFFER_SIZE);
+
+  /* extern int snprintf(char *str, size_t size, const char *format, ...); */
+  gcc_jit_param *param_s =
+    gcc_jit_context_new_param (ctxt, NULL, char_ptr_type, "s");
+  gcc_jit_param *param_n =
+    gcc_jit_context_new_param (ctxt, NULL, size_t_type, "n");
+  gcc_jit_param *param_format =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "format");
+  gcc_jit_param *snprintf_params[3] = {param_s, param_n, param_format};
+  gcc_jit_function *snprintf =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_IMPORTED,
+				  int_type,
+				  "snprintf",
+				  3, snprintf_params,
+				  1);
+
+  gcc_jit_param *param_name =
+    gcc_jit_context_new_param (ctxt, NULL, const_char_ptr_type, "name");
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+				  GCC_JIT_FUNCTION_EXPORTED,
+				  void_type,
+				  "test_of_array_as_pointer",
+				  1, &param_name,
+				  0);
+
+  gcc_jit_lvalue *buffer =
+    gcc_jit_context_new_global (ctxt, NULL, buf_type, "test_buffer");
+
+  gcc_jit_block *block = gcc_jit_function_new_block(test_fn, "entry");
+
+  /* snprintf(buffer, sizeof(buffer), "hello %s", name); */
+  gcc_jit_rvalue *args[4];
+  args[0] = gcc_jit_context_new_cast (
+    ctxt, NULL,
+    /* Here's the difference with test-array-as-pointer.c: */
+    gcc_jit_lvalue_as_rvalue (buffer),
+    char_ptr_type);
+  args[1] = gcc_jit_context_new_rvalue_from_int (ctxt,
+						 size_t_type,
+						 BUFFER_SIZE);
+  args[2] = gcc_jit_context_new_string_literal (ctxt, "hello %s");
+  args[3] = gcc_jit_param_as_rvalue (param_name);
+
+  gcc_jit_block_add_eval (
+    block, NULL,
+    gcc_jit_context_new_call (ctxt, NULL, snprintf, 4, args));
+  gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  CHECK_VALUE (result, NULL);
+
+  /* Verify that the correct error message was emitted.  */
+  CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+		      "gcc_jit_context_new_cast:"
+		      " cannot cast test_buffer"
+		      " from type: char[1024]"
+		      " to type: char *");
+}