diff mbox

[jit] Add type-checking to gcc_jit_context_new_cast

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

Commit Message

David Malcolm March 14, 2014, 1:18 a.m. UTC
Committed to branch dmalcolm/jit:

gcc/jit/
	* libgccjit.c (is_valid_cast): New.
	(gcc_jit_context_new_cast): Check for compatible types.

	* internal-api.c (gcc::jit::recording::memento_of_get_type::
	is_int): New.
	(gcc::jit::recording::memento_of_get_type::is_float): New.
	(gcc::jit::recording::memento_of_get_type::is_bool): New.

	* internal-api.h (gcc::jit::recording::type::is_int): New.
	(gcc::jit::recording::type::is_float): New.
	(gcc::jit::recording::type::is_bool): New.

	(gcc::jit::recording::memento_of_get_type::is_int): New.
	(gcc::jit::recording::memento_of_get_type::is_float): New.
	(gcc::jit::recording::memento_of_get_type::is_bool): New.

	(gcc::jit::recording::memento_of_get_pointer::is_int): New.
	(gcc::jit::recording::memento_of_get_pointer::is_float): New.
	(gcc::jit::recording::memento_of_get_pointer::is_bool): New.

	(gcc::jit::recording::memento_of_get_const::is_int): New.
	(gcc::jit::recording::memento_of_get_const::is_float): New.
	(gcc::jit::recording::memento_of_get_const::is_bool): New.

	(gcc::jit::recording::memento_of_get_volatile::is_int): New.
	(gcc::jit::recording::memento_of_get_volatile::is_float): New.
	(gcc::jit::recording::memento_of_get_volatile::is_bool): New.

	(gcc::jit::recording::array_type::is_int): New.
	(gcc::jit::recording::array_type::is_float): New.
	(gcc::jit::recording::array_type::is_bool): New.

	(gcc::jit::recording::function_type::is_int): New.
	(gcc::jit::recording::function_type::is_float): New.
	(gcc::jit::recording::function_type::is_bool): New.

	(gcc::jit::recording::struct_::is_int): New.
	(gcc::jit::recording::struct_::is_float): New.
	(gcc::jit::recording::struct_::is_bool): New.

gcc/testsuite/
	* jit.dg/test-error-bad-cast.c: New test case.
---
 gcc/jit/ChangeLog.jit                      |  42 +++++++++
 gcc/jit/internal-api.c                     | 135 +++++++++++++++++++++++++++++
 gcc/jit/internal-api.h                     |  33 +++++++
 gcc/jit/libgccjit.c                        |  33 +++++++
 gcc/testsuite/ChangeLog.jit                |   4 +
 gcc/testsuite/jit.dg/test-error-bad-cast.c |  63 ++++++++++++++
 6 files changed, 310 insertions(+)
 create mode 100644 gcc/testsuite/jit.dg/test-error-bad-cast.c
diff mbox

Patch

diff --git a/gcc/jit/ChangeLog.jit b/gcc/jit/ChangeLog.jit
index 87f10a3..260273c 100644
--- a/gcc/jit/ChangeLog.jit
+++ b/gcc/jit/ChangeLog.jit
@@ -1,5 +1,47 @@ 
 2014-03-13  David Malcolm  <dmalcolm@redhat.com>
 
+	* libgccjit.c (is_valid_cast): New.
+	(gcc_jit_context_new_cast): Check for compatible types.
+
+	* internal-api.c (gcc::jit::recording::memento_of_get_type::
+	is_int): New.
+	(gcc::jit::recording::memento_of_get_type::is_float): New.
+	(gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+	* internal-api.h (gcc::jit::recording::type::is_int): New.
+	(gcc::jit::recording::type::is_float): New.
+	(gcc::jit::recording::type::is_bool): New.
+
+	(gcc::jit::recording::memento_of_get_type::is_int): New.
+	(gcc::jit::recording::memento_of_get_type::is_float): New.
+	(gcc::jit::recording::memento_of_get_type::is_bool): New.
+
+	(gcc::jit::recording::memento_of_get_pointer::is_int): New.
+	(gcc::jit::recording::memento_of_get_pointer::is_float): New.
+	(gcc::jit::recording::memento_of_get_pointer::is_bool): New.
+
+	(gcc::jit::recording::memento_of_get_const::is_int): New.
+	(gcc::jit::recording::memento_of_get_const::is_float): New.
+	(gcc::jit::recording::memento_of_get_const::is_bool): New.
+
+	(gcc::jit::recording::memento_of_get_volatile::is_int): New.
+	(gcc::jit::recording::memento_of_get_volatile::is_float): New.
+	(gcc::jit::recording::memento_of_get_volatile::is_bool): New.
+
+	(gcc::jit::recording::array_type::is_int): New.
+	(gcc::jit::recording::array_type::is_float): New.
+	(gcc::jit::recording::array_type::is_bool): New.
+
+	(gcc::jit::recording::function_type::is_int): New.
+	(gcc::jit::recording::function_type::is_float): New.
+	(gcc::jit::recording::function_type::is_bool): New.
+
+	(gcc::jit::recording::struct_::is_int): New.
+	(gcc::jit::recording::struct_::is_float): New.
+	(gcc::jit::recording::struct_::is_bool): New.
+
+2014-03-13  David Malcolm  <dmalcolm@redhat.com>
+
 	* internal-api.c (gcc::jit::recording::context::set_str_option):
 	Provide NULL recording::location to add_error.
 	(gcc::jit::recording::context::set_int_option): Likewise.
diff --git a/gcc/jit/internal-api.c b/gcc/jit/internal-api.c
index 692dffb..062095e 100644
--- a/gcc/jit/internal-api.c
+++ b/gcc/jit/internal-api.c
@@ -856,6 +856,141 @@  recording::memento_of_get_type::dereference ()
     }
 }
 
+bool
+recording::memento_of_get_type::is_int () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return true;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return true;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+bool
+recording::memento_of_get_type::is_float () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return false;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return true;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
+bool
+recording::memento_of_get_type::is_bool () const
+{
+  switch (m_kind)
+    {
+    default: gcc_unreachable ();
+
+    case GCC_JIT_TYPE_VOID:
+      return false;
+
+    case GCC_JIT_TYPE_VOID_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_BOOL:
+      return true;
+
+    case GCC_JIT_TYPE_CHAR:
+    case GCC_JIT_TYPE_SIGNED_CHAR:
+    case GCC_JIT_TYPE_UNSIGNED_CHAR:
+    case GCC_JIT_TYPE_SHORT:
+    case GCC_JIT_TYPE_UNSIGNED_SHORT:
+    case GCC_JIT_TYPE_INT:
+    case GCC_JIT_TYPE_UNSIGNED_INT:
+    case GCC_JIT_TYPE_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG:
+    case GCC_JIT_TYPE_LONG_LONG:
+    case GCC_JIT_TYPE_UNSIGNED_LONG_LONG:
+      return false;
+
+    case GCC_JIT_TYPE_FLOAT:
+    case GCC_JIT_TYPE_DOUBLE:
+    case GCC_JIT_TYPE_LONG_DOUBLE:
+      return false;
+
+    case GCC_JIT_TYPE_CONST_CHAR_PTR:
+      return false;
+
+    case GCC_JIT_TYPE_SIZE_T:
+      return false;
+
+    case GCC_JIT_TYPE_FILE_PTR:
+      return false;
+    }
+}
+
 void
 recording::memento_of_get_type::replay_into (replayer *r)
 {
diff --git a/gcc/jit/internal-api.h b/gcc/jit/internal-api.h
index 5048f41..772f828 100644
--- a/gcc/jit/internal-api.h
+++ b/gcc/jit/internal-api.h
@@ -493,6 +493,9 @@  public:
     return this;
   }
 
+  virtual bool is_int () const = 0;
+  virtual bool is_float () const = 0;
+  virtual bool is_bool () const = 0;
 
   playback::type *
   playback_type ()
@@ -534,6 +537,10 @@  public:
     return type::accepts_writes_from (rtype);
   }
 
+  bool is_int () const;
+  bool is_float () const;
+  bool is_bool () const;
+
 public:
   void replay_into (replayer *r);
 
@@ -558,6 +565,10 @@  public:
 
   void replay_into (replayer *r);
 
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+
 private:
   string * make_debug_string ();
 
@@ -584,6 +595,10 @@  public:
   /* Strip off the "const", giving the underlying type.  */
   type *unqualified () { return m_other_type; }
 
+  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 (); }
+
   void replay_into (replayer *);
 
 private:
@@ -606,6 +621,10 @@  public:
   /* Strip off the "volatile", giving the underlying type.  */
   type *unqualified () { return m_other_type; }
 
+  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 (); }
+
   void replay_into (replayer *);
 
 private:
@@ -629,6 +648,11 @@  class array_type : public type
   {}
 
   type *dereference ();
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+
   void replay_into (replayer *);
 
  private:
@@ -651,6 +675,11 @@  public:
 
   type *dereference ();
   function_type *as_a_function_type () { return this; }
+
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+
   void replay_into (replayer *);
 
   type * get_return_type () const { return m_return_type; }
@@ -724,6 +753,10 @@  public:
 
   type *dereference ();
 
+  bool is_int () const { return false; }
+  bool is_float () const { return false; }
+  bool is_bool () const { return false; }
+
   void replay_into (replayer *r);
 
   playback::struct_ *
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 936576c..baab60d 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -882,6 +882,32 @@  gcc_jit_context_new_call (gcc_jit_context *ctxt,
 					   (gcc::jit::recording::rvalue **)args);
 }
 
+static bool
+is_valid_cast (gcc::jit::recording::type *src_type,
+	       gcc_jit_type *dst_type)
+{
+  bool src_is_int = src_type->is_int ();
+  bool dst_is_int = dst_type->is_int ();
+  bool src_is_float = src_type->is_float ();
+  bool dst_is_float = dst_type->is_float ();
+  bool src_is_bool = src_type->is_bool ();
+  bool dst_is_bool = dst_type->is_bool ();
+
+  if (src_is_int)
+    if (dst_is_int || dst_is_float || dst_is_bool)
+      return true;
+
+  if (src_is_float)
+    if (dst_is_int || dst_is_float)
+      return true;
+
+  if (src_is_bool)
+    if (dst_is_int || dst_is_bool)
+      return true;
+
+  return false;
+}
+
 gcc_jit_rvalue *
 gcc_jit_context_new_cast (gcc_jit_context *ctxt,
 			  gcc_jit_location *loc,
@@ -891,6 +917,13 @@  gcc_jit_context_new_cast (gcc_jit_context *ctxt,
   RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL context");
   RETURN_NULL_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
   RETURN_NULL_IF_FAIL (type, ctxt, loc, "NULL type");
+  RETURN_NULL_IF_FAIL_PRINTF3 (
+    is_valid_cast (rvalue->get_type (), type),
+    ctxt, loc,
+    "cannot cast %s from type: %s to type: %s",
+    rvalue->get_debug_string (),
+    rvalue->get_type ()->get_debug_string (),
+    type->get_debug_string ());
 
   return static_cast <gcc_jit_rvalue *> (ctxt->new_cast (loc, rvalue, type));
 }
diff --git a/gcc/testsuite/ChangeLog.jit b/gcc/testsuite/ChangeLog.jit
index 5a84bfd..b8f1fa8 100644
--- a/gcc/testsuite/ChangeLog.jit
+++ b/gcc/testsuite/ChangeLog.jit
@@ -1,3 +1,7 @@ 
+2014-03-13  David Malcolm  <dmalcolm@redhat.com>
+
+	* jit.dg/test-error-bad-cast.c: New test case.
+
 2014-03-11  David Malcolm  <dmalcolm@redhat.com>
 
 	* jit.dg/harness.h (set_options): Increase optimization level from
diff --git a/gcc/testsuite/jit.dg/test-error-bad-cast.c b/gcc/testsuite/jit.dg/test-error-bad-cast.c
new file mode 100644
index 0000000..a0ab413
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-bad-cast.c
@@ -0,0 +1,63 @@ 
+#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:
+
+     int
+     test_fn ()
+     {
+       struct foo f;
+       return (int)f;
+     }
+
+     and verify that the API complains about the bad cast.
+  */
+  gcc_jit_type *int_type =
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+
+  gcc_jit_struct *struct_foo =
+    gcc_jit_context_new_struct_type (ctxt, NULL, "foo",
+				     0, NULL);
+
+  gcc_jit_function *test_fn =
+    gcc_jit_context_new_function (ctxt, NULL,
+                                  GCC_JIT_FUNCTION_EXPORTED,
+                                  int_type,
+                                  "test_fn",
+                                  0, NULL,
+                                  0);
+  gcc_jit_lvalue *f =
+    gcc_jit_function_new_local (
+      test_fn,
+      NULL,
+      gcc_jit_struct_as_type (struct_foo), "f");
+
+  gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+  gcc_jit_block_end_with_return (
+    block, NULL,
+    gcc_jit_context_new_cast (ctxt, NULL,
+			      gcc_jit_lvalue_as_rvalue (f),
+			      int_type));
+}
+
+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 f from type: struct foo"
+		      " to type: int");
+}
+