Commit f6f2b019 by David Malcolm Committed by David Malcolm

libgccjit: detect various kinds of errors relating to params and locals

gcc/jit/ChangeLog:
	* jit-recording.c (class gcc::jit::rvalue_usage_validator): New.
	(gcc::jit::rvalue_usage_validator::rvalue_usage_validator): New
	ctor.
	(gcc::jit::rvalue_usage_validator::visit): New function.
	(gcc::jit::recording::rvalue::verify_valid_within_stmt): New
	function.
	(gcc::jit::recording::rvalue::set_scope): New function.
	(gcc::jit::recording::function::function): Call set_scope on each
	param, issuing errors for any params that already have a function.
	(gcc::jit::recording::block::add_eval): Return the new statement;
	update the comment given that some error-checking now happens after
	this returns.
	(gcc::jit::recording::block::add_assignment): Likewise.
	(gcc::jit::recording::block::add_assignment_op): Likewise.
	(gcc::jit::recording::block::add_comment): Likewise.
	(gcc::jit::recording::block::end_with_conditional): Likewise.
	(gcc::jit::recording::block::end_with_jump): Likewise.
	(gcc::jit::recording::block::end_with_return): Likewise.
	(gcc::jit::recording::block::validate): Add a comment.
	(gcc::jit::recording::unary_op::visit_children): New function.
	(gcc::jit::recording::binary_op::visit_children): New function.
	(gcc::jit::recording::comparison::visit_children): New function.
	(gcc::jit::recording::cast::visit_children): New function.
	(gcc::jit::recording::call::visit_children): New function.
	(gcc::jit::recording::call_through_ptr::visit_children): New function.
	(gcc::jit::recording::array_access::visit_children): New function.
	(gcc::jit::recording::access_field_of_lvalue::visit_children): New
	function.
	(gcc::jit::recording::access_field_rvalue::visit_children): New
	function.
	(gcc::jit::recording::dereference_field_rvalue::visit_children):
	New function.
	(gcc::jit::recording::dereference_rvalue::visit_children): New
	function.
	(gcc::jit::recording::get_address_of_lvalue::visit_children): New
	function.
	* jit-recording.h: Within namespace gcc::jit::recording...
	(class rvalue_visitor): New.
	(rvalue::rvalue): Initialize m_scope.
	(rvalue::get_loc): New accessor.
	(rvalue::verify_valid_within_stmt): New function.
	(rvalue::visit_children): New pure virtual function.
	(rvalue::set_scope): New function.
	(rvalue::get_scope): New function.
	(rvalue::dyn_cast_param): New function.
	(rvalue::m_scope): New field.
	(param::visit_children): New empty function.
	(param::dyn_cast_param): New function.
	(function::get_loc): New function.
	(block::add_eval): Return the new statement.
	(block::add_assignment): Likewise.
	(block::add_assignment_op): Likewise.
	(block::add_comment): Likewise.
	(block::end_with_conditional): Likewise.
	(block::end_with_jump): Likewise.
	(block::end_with_return): Likewise.
	(global::visit_children): New function.
	(memento_of_new_rvalue_from_const<HOST_TYPE>::visit_children):
	New function.
	(memento_of_new_string_literal::visit_children): New function.
	(unary_op::visit_children): New function.
	(binary_op::visit_children): New function.
	(comparison::visit_children): New function.
	(cast::visit_children): New function.
	(call::visit_children): New function.
	(call_through_ptr::visit_children): New function.
	(array_access::visit_children): New function.
	(access_field_of_lvalue::visit_children): New function.
	(access_field_rvalue::visit_children): New function.
	(dereference_field_rvalue::visit_children): New function.
	(dereference_rvalue::visit_children): New function.
	(get_address_of_lvalue::visit_children): New function.
	(local::local): Call set_scope.
	(local::visit_children): New function.
	(statement::get_block): Make public.
	* libgccjit.c (RETURN_VAL_IF_FAIL_PRINTF5): New macro.
	(RETURN_NULL_IF_FAIL_PRINTF5): New macro.
	(gcc_jit_context_new_function): Verify that each param has
	not yet been used for creating another function.
	(gcc_jit_block_add_eval): After creating the stmt, verify
	that the rvalue expression tree is valid to use within it.
	(gcc_jit_block_add_assignment): Likewise for the lvalue and
	rvalue expression trees.
	(gcc_jit_block_add_assignment_op): Likewise.
	(gcc_jit_block_end_with_conditional): Likewise for the boolval
	expression tree.
	(gcc_jit_block_end_with_return): Likewise for the rvalue
	expression tree.
	(gcc_jit_block_end_with_void_return): Remove return of "void",
	now that block::end_with_return is now non-void.

gcc/testsuite/ChangeLog:
	* jit.dg/test-error-local-used-from-other-function.c: New test
	case.
	* jit.dg/test-error-param-reuse.c: New test case.
	* jit.dg/test-error-param-sharing.c: New test case.
	* jit.dg/test-error-param-used-from-other-function.c: New test
	case.
	* jit.dg/test-error-param-used-without-a-function.c: New test
	case.

From-SVN: r219498
parent 16ba6203
2015-01-12 David Malcolm <dmalcolm@redhat.com> 2015-01-12 David Malcolm <dmalcolm@redhat.com>
* jit-recording.c (class gcc::jit::rvalue_usage_validator): New.
(gcc::jit::rvalue_usage_validator::rvalue_usage_validator): New
ctor.
(gcc::jit::rvalue_usage_validator::visit): New function.
(gcc::jit::recording::rvalue::verify_valid_within_stmt): New
function.
(gcc::jit::recording::rvalue::set_scope): New function.
(gcc::jit::recording::function::function): Call set_scope on each
param, issuing errors for any params that already have a function.
(gcc::jit::recording::block::add_eval): Return the new statement;
update the comment given that some error-checking now happens after
this returns.
(gcc::jit::recording::block::add_assignment): Likewise.
(gcc::jit::recording::block::add_assignment_op): Likewise.
(gcc::jit::recording::block::add_comment): Likewise.
(gcc::jit::recording::block::end_with_conditional): Likewise.
(gcc::jit::recording::block::end_with_jump): Likewise.
(gcc::jit::recording::block::end_with_return): Likewise.
(gcc::jit::recording::block::validate): Add a comment.
(gcc::jit::recording::unary_op::visit_children): New function.
(gcc::jit::recording::binary_op::visit_children): New function.
(gcc::jit::recording::comparison::visit_children): New function.
(gcc::jit::recording::cast::visit_children): New function.
(gcc::jit::recording::call::visit_children): New function.
(gcc::jit::recording::call_through_ptr::visit_children): New function.
(gcc::jit::recording::array_access::visit_children): New function.
(gcc::jit::recording::access_field_of_lvalue::visit_children): New
function.
(gcc::jit::recording::access_field_rvalue::visit_children): New
function.
(gcc::jit::recording::dereference_field_rvalue::visit_children):
New function.
(gcc::jit::recording::dereference_rvalue::visit_children): New
function.
(gcc::jit::recording::get_address_of_lvalue::visit_children): New
function.
* jit-recording.h: Within namespace gcc::jit::recording...
(class rvalue_visitor): New.
(rvalue::rvalue): Initialize m_scope.
(rvalue::get_loc): New accessor.
(rvalue::verify_valid_within_stmt): New function.
(rvalue::visit_children): New pure virtual function.
(rvalue::set_scope): New function.
(rvalue::get_scope): New function.
(rvalue::dyn_cast_param): New function.
(rvalue::m_scope): New field.
(param::visit_children): New empty function.
(param::dyn_cast_param): New function.
(function::get_loc): New function.
(block::add_eval): Return the new statement.
(block::add_assignment): Likewise.
(block::add_assignment_op): Likewise.
(block::add_comment): Likewise.
(block::end_with_conditional): Likewise.
(block::end_with_jump): Likewise.
(block::end_with_return): Likewise.
(global::visit_children): New function.
(memento_of_new_rvalue_from_const<HOST_TYPE>::visit_children):
New function.
(memento_of_new_string_literal::visit_children): New function.
(unary_op::visit_children): New function.
(binary_op::visit_children): New function.
(comparison::visit_children): New function.
(cast::visit_children): New function.
(call::visit_children): New function.
(call_through_ptr::visit_children): New function.
(array_access::visit_children): New function.
(access_field_of_lvalue::visit_children): New function.
(access_field_rvalue::visit_children): New function.
(dereference_field_rvalue::visit_children): New function.
(dereference_rvalue::visit_children): New function.
(get_address_of_lvalue::visit_children): New function.
(local::local): Call set_scope.
(local::visit_children): New function.
(statement::get_block): Make public.
* libgccjit.c (RETURN_VAL_IF_FAIL_PRINTF5): New macro.
(RETURN_NULL_IF_FAIL_PRINTF5): New macro.
(gcc_jit_context_new_function): Verify that each param has
not yet been used for creating another function.
(gcc_jit_block_add_eval): After creating the stmt, verify
that the rvalue expression tree is valid to use within it.
(gcc_jit_block_add_assignment): Likewise for the lvalue and
rvalue expression trees.
(gcc_jit_block_add_assignment_op): Likewise.
(gcc_jit_block_end_with_conditional): Likewise for the boolval
expression tree.
(gcc_jit_block_end_with_return): Likewise for the rvalue
expression tree.
(gcc_jit_block_end_with_void_return): Remove return of "void",
now that block::end_with_return is now non-void.
2015-01-12 David Malcolm <dmalcolm@redhat.com>
* jit-playback.c (gcc::jit::playback::context::read_dump_file): * jit-playback.c (gcc::jit::playback::context::read_dump_file):
Add missing fclose on error-handling path. Add missing fclose on error-handling path.
......
...@@ -2034,6 +2034,115 @@ recording::rvalue::dereference (recording::location *loc) ...@@ -2034,6 +2034,115 @@ recording::rvalue::dereference (recording::location *loc)
return result; return result;
} }
/* An rvalue visitor, for validating that every rvalue within an expression
trees within "STMT" has the correct scope (e.g. no access to locals
of a different function). */
class rvalue_usage_validator : public recording::rvalue_visitor
{
public:
rvalue_usage_validator (const char *api_funcname,
recording::context *ctxt,
recording::statement *stmt);
void
visit (recording::rvalue *rvalue);
private:
const char *m_api_funcname;
recording::context *m_ctxt;
recording::statement *m_stmt;
};
/* The trivial constructor for rvalue_usage_validator. */
rvalue_usage_validator::rvalue_usage_validator (const char *api_funcname,
recording::context *ctxt,
recording::statement *stmt)
: m_api_funcname (api_funcname),
m_ctxt (ctxt),
m_stmt (stmt)
{
}
/* Verify that the given rvalue is in the correct scope. */
void
rvalue_usage_validator::visit (recording::rvalue *rvalue)
{
gcc_assert (m_stmt->get_block ());
recording::function *stmt_scope = m_stmt->get_block ()->get_function ();
/* Most rvalues don't have a scope (only locals and params). */
if (rvalue->get_scope ())
{
if (rvalue->get_scope () != stmt_scope)
m_ctxt->add_error
(rvalue->get_loc (),
"%s:"
" rvalue %s (type: %s)"
" has scope limited to function %s"
" but was used within function %s"
" (in statement: %s)",
m_api_funcname,
rvalue->get_debug_string (),
rvalue->get_type ()->get_debug_string (),
rvalue->get_scope ()->get_debug_string (),
stmt_scope->get_debug_string (),
m_stmt->get_debug_string ());
}
else
{
if (rvalue->dyn_cast_param ())
m_ctxt->add_error
(rvalue->get_loc (),
"%s:"
" param %s (type: %s)"
" was used within function %s"
" (in statement: %s)"
" but is not associated with any function",
m_api_funcname,
rvalue->get_debug_string (),
rvalue->get_type ()->get_debug_string (),
stmt_scope->get_debug_string (),
m_stmt->get_debug_string ());
}
}
/* Verify that it's valid to use this rvalue (and all expressions
in the tree below it) within the given statement.
For example, we must reject attempts to use a local from one
function within a different function here, or we'll get
an ICE deep inside toplev::main. */
void
recording::rvalue::verify_valid_within_stmt (const char *api_funcname, statement *s)
{
rvalue_usage_validator v (api_funcname,
s->get_context (),
s);
/* Verify that it's OK to use this rvalue within s. */
v.visit (this);
/* Traverse the expression tree below "this", verifying all rvalues
within it. */
visit_children (&v);
}
/* Set the scope of this rvalue to be the given function. This can only
be done once on a given rvalue. */
void
recording::rvalue::set_scope (function *scope)
{
gcc_assert (scope);
gcc_assert (NULL == m_scope);
m_scope = scope;
}
/* The implementation of class gcc::jit::recording::lvalue. */ /* The implementation of class gcc::jit::recording::lvalue. */
/* Create a recording::new_access_field_of_lvalue instance and add it to /* Create a recording::new_access_field_of_lvalue instance and add it to
...@@ -2106,7 +2215,40 @@ recording::function::function (context *ctxt, ...@@ -2106,7 +2215,40 @@ recording::function::function (context *ctxt,
m_blocks () m_blocks ()
{ {
for (int i = 0; i< num_params; i++) for (int i = 0; i< num_params; i++)
m_params.safe_push (params[i]); {
param *param = params[i];
gcc_assert (param);
/* Associate each param with this function.
Verify that the param doesn't already have a function. */
if (param->get_scope ())
{
/* We've already rejected attempts to reuse a param between
different functions (within gcc_jit_context_new_function), so
if the param *does* already have a function, it must be being
reused within the params array for this function. We must
produce an error for this reuse (blocking the compile), since
otherwise we'd have an ICE later on. */
gcc_assert (this == param->get_scope ());
ctxt->add_error
(loc,
"gcc_jit_context_new_function:"
" parameter %s (type: %s)"
" is used more than once when creating function %s",
param->get_debug_string (),
param->get_type ()->get_debug_string (),
name->c_str ());
}
else
{
/* The normal, non-error case: associate this function with the
param. */
param->set_scope (this);
}
m_params.safe_push (param);
}
} }
/* Implementation of pure virtual hook recording::memento::replay_into /* Implementation of pure virtual hook recording::memento::replay_into
...@@ -2366,26 +2508,25 @@ recording::function::make_debug_string () ...@@ -2366,26 +2508,25 @@ recording::function::make_debug_string ()
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_add_eval. */
gcc_jit_block_add_eval. */
void recording::statement *
recording::block::add_eval (recording::location *loc, recording::block::add_eval (recording::location *loc,
recording::rvalue *rvalue) recording::rvalue *rvalue)
{ {
statement *result = new eval (this, loc, rvalue); statement *result = new eval (this, loc, rvalue);
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
return result;
} }
/* Create a recording::assignment instance and add it to /* Create a recording::assignment instance and add it to
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_add_assignment. */
gcc_jit_block_add_assignment. */
void recording::statement *
recording::block::add_assignment (recording::location *loc, recording::block::add_assignment (recording::location *loc,
recording::lvalue *lvalue, recording::lvalue *lvalue,
recording::rvalue *rvalue) recording::rvalue *rvalue)
...@@ -2393,16 +2534,16 @@ recording::block::add_assignment (recording::location *loc, ...@@ -2393,16 +2534,16 @@ recording::block::add_assignment (recording::location *loc,
statement *result = new assignment (this, loc, lvalue, rvalue); statement *result = new assignment (this, loc, lvalue, rvalue);
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
return result;
} }
/* Create a recording::assignment_op instance and add it to /* Create a recording::assignment_op instance and add it to
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_add_assignment_op. */
gcc_jit_block_add_assignment_op. */
void recording::statement *
recording::block::add_assignment_op (recording::location *loc, recording::block::add_assignment_op (recording::location *loc,
recording::lvalue *lvalue, recording::lvalue *lvalue,
enum gcc_jit_binary_op op, enum gcc_jit_binary_op op,
...@@ -2411,32 +2552,32 @@ recording::block::add_assignment_op (recording::location *loc, ...@@ -2411,32 +2552,32 @@ recording::block::add_assignment_op (recording::location *loc,
statement *result = new assignment_op (this, loc, lvalue, op, rvalue); statement *result = new assignment_op (this, loc, lvalue, op, rvalue);
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
return result;
} }
/* Create a recording::comment instance and add it to /* Create a recording::comment instance and add it to
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_add_comment. */
gcc_jit_block_add_comment. */
void recording::statement *
recording::block::add_comment (recording::location *loc, recording::block::add_comment (recording::location *loc,
const char *text) const char *text)
{ {
statement *result = new comment (this, loc, new_string (text)); statement *result = new comment (this, loc, new_string (text));
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
return result;
} }
/* Create a recording::end_with_conditional instance and add it to /* Create a recording::end_with_conditional instance and add it to
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_end_with_conditional. */
gcc_jit_block_end_with_conditional. */
void recording::statement *
recording::block::end_with_conditional (recording::location *loc, recording::block::end_with_conditional (recording::location *loc,
recording::rvalue *boolval, recording::rvalue *boolval,
recording::block *on_true, recording::block *on_true,
...@@ -2446,16 +2587,16 @@ recording::block::end_with_conditional (recording::location *loc, ...@@ -2446,16 +2587,16 @@ recording::block::end_with_conditional (recording::location *loc,
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
m_has_been_terminated = true; m_has_been_terminated = true;
return result;
} }
/* Create a recording::end_with_jump instance and add it to /* Create a recording::end_with_jump instance and add it to
the block's context's list of mementos, and to the block's the block's context's list of mementos, and to the block's
list of statements. list of statements.
Implements the post-error-checking part of Implements the heart of gcc_jit_block_end_with_jump. */
gcc_jit_block_end_with_jump. */
void recording::statement *
recording::block::end_with_jump (recording::location *loc, recording::block::end_with_jump (recording::location *loc,
recording::block *target) recording::block *target)
{ {
...@@ -2463,6 +2604,7 @@ recording::block::end_with_jump (recording::location *loc, ...@@ -2463,6 +2604,7 @@ recording::block::end_with_jump (recording::location *loc,
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
m_has_been_terminated = true; m_has_been_terminated = true;
return result;
} }
/* Create a recording::end_with_return instance and add it to /* Create a recording::end_with_return instance and add it to
...@@ -2473,7 +2615,7 @@ recording::block::end_with_jump (recording::location *loc, ...@@ -2473,7 +2615,7 @@ recording::block::end_with_jump (recording::location *loc,
gcc_jit_block_end_with_return and gcc_jit_block_end_with_return and
gcc_jit_block_end_with_void_return. */ gcc_jit_block_end_with_void_return. */
void recording::statement *
recording::block::end_with_return (recording::location *loc, recording::block::end_with_return (recording::location *loc,
recording::rvalue *rvalue) recording::rvalue *rvalue)
{ {
...@@ -2484,6 +2626,7 @@ recording::block::end_with_return (recording::location *loc, ...@@ -2484,6 +2626,7 @@ recording::block::end_with_return (recording::location *loc,
m_ctxt->record (result); m_ctxt->record (result);
m_statements.safe_push (result); m_statements.safe_push (result);
m_has_been_terminated = true; m_has_been_terminated = true;
return result;
} }
/* Override the default implementation of /* Override the default implementation of
...@@ -2513,6 +2656,7 @@ recording::block::write_to_dump (dump &d) ...@@ -2513,6 +2656,7 @@ recording::block::write_to_dump (dump &d)
bool bool
recording::block::validate () recording::block::validate ()
{ {
/* Check for termination. */
if (!has_been_terminated ()) if (!has_been_terminated ())
{ {
statement *stmt = get_last_statement (); statement *stmt = get_last_statement ();
...@@ -2856,6 +3000,14 @@ recording::unary_op::replay_into (replayer *r) ...@@ -2856,6 +3000,14 @@ recording::unary_op::replay_into (replayer *r)
m_a->playback_rvalue ())); m_a->playback_rvalue ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::unary_op. */
void
recording::unary_op::visit_children (rvalue_visitor *v)
{
v->visit (m_a);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
unary ops. */ unary ops. */
...@@ -2890,6 +3042,15 @@ recording::binary_op::replay_into (replayer *r) ...@@ -2890,6 +3042,15 @@ recording::binary_op::replay_into (replayer *r)
m_b->playback_rvalue ())); m_b->playback_rvalue ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::binary_op. */
void
recording::binary_op::visit_children (rvalue_visitor *v)
{
v->visit (m_a);
v->visit (m_b);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
binary ops. */ binary ops. */
...@@ -2955,6 +3116,16 @@ recording::comparison::replay_into (replayer *r) ...@@ -2955,6 +3116,16 @@ recording::comparison::replay_into (replayer *r)
m_b->playback_rvalue ())); m_b->playback_rvalue ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::comparison. */
void
recording::comparison::visit_children (rvalue_visitor *v)
{
v->visit (m_a);
v->visit (m_b);
}
/* Implementation of pure virtual hook recording::memento::replay_into /* Implementation of pure virtual hook recording::memento::replay_into
for recording::cast. */ for recording::cast. */
...@@ -2966,6 +3137,14 @@ recording::cast::replay_into (replayer *r) ...@@ -2966,6 +3137,14 @@ recording::cast::replay_into (replayer *r)
get_type ()->playback_type ())); get_type ()->playback_type ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::cast. */
void
recording::cast::visit_children (rvalue_visitor *v)
{
v->visit (m_rvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
casts. */ casts. */
...@@ -3011,6 +3190,16 @@ recording::call::replay_into (replayer *r) ...@@ -3011,6 +3190,16 @@ recording::call::replay_into (replayer *r)
&playback_args)); &playback_args));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::call. */
void
recording::call::visit_children (rvalue_visitor *v)
{
for (unsigned i = 0; i< m_args.length (); i++)
v->visit (m_args[i]);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
function calls. */ function calls. */
...@@ -3088,6 +3277,17 @@ recording::call_through_ptr::replay_into (replayer *r) ...@@ -3088,6 +3277,17 @@ recording::call_through_ptr::replay_into (replayer *r)
&playback_args)); &playback_args));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::call_through_ptr. */
void
recording::call_through_ptr::visit_children (rvalue_visitor *v)
{
v->visit (m_fn_ptr);
for (unsigned i = 0; i< m_args.length (); i++)
v->visit (m_args[i]);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
calls through function ptrs. */ calls through function ptrs. */
...@@ -3144,6 +3344,16 @@ recording::array_access::replay_into (replayer *r) ...@@ -3144,6 +3344,16 @@ recording::array_access::replay_into (replayer *r)
m_index->playback_rvalue ())); m_index->playback_rvalue ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::array_access. */
void
recording::array_access::visit_children (rvalue_visitor *v)
{
v->visit (m_ptr);
v->visit (m_index);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
array accesses. */ array accesses. */
...@@ -3171,6 +3381,15 @@ recording::access_field_of_lvalue::replay_into (replayer *r) ...@@ -3171,6 +3381,15 @@ recording::access_field_of_lvalue::replay_into (replayer *r)
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::access_field_of_lvalue. */
void
recording::access_field_of_lvalue::visit_children (rvalue_visitor *v)
{
v->visit (m_lvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
accessing a field of an lvalue. */ accessing a field of an lvalue. */
...@@ -3197,6 +3416,15 @@ recording::access_field_rvalue::replay_into (replayer *r) ...@@ -3197,6 +3416,15 @@ recording::access_field_rvalue::replay_into (replayer *r)
m_field->playback_field ())); m_field->playback_field ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::access_field_rvalue. */
void
recording::access_field_rvalue::visit_children (rvalue_visitor *v)
{
v->visit (m_rvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
accessing a field of an rvalue. */ accessing a field of an rvalue. */
...@@ -3224,6 +3452,15 @@ recording::dereference_field_rvalue::replay_into (replayer *r) ...@@ -3224,6 +3452,15 @@ recording::dereference_field_rvalue::replay_into (replayer *r)
m_field->playback_field ())); m_field->playback_field ()));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::dereference_field_rvalue. */
void
recording::dereference_field_rvalue::visit_children (rvalue_visitor *v)
{
v->visit (m_rvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
dereferencing a field of an rvalue. */ dereferencing a field of an rvalue. */
...@@ -3249,6 +3486,15 @@ recording::dereference_rvalue::replay_into (replayer *r) ...@@ -3249,6 +3486,15 @@ recording::dereference_rvalue::replay_into (replayer *r)
dereference (playback_location (r, m_loc))); dereference (playback_location (r, m_loc)));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::dereference_rvalue. */
void
recording::dereference_rvalue::visit_children (rvalue_visitor *v)
{
v->visit (m_rvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
dereferencing an rvalue. */ dereferencing an rvalue. */
...@@ -3273,6 +3519,15 @@ recording::get_address_of_lvalue::replay_into (replayer *r) ...@@ -3273,6 +3519,15 @@ recording::get_address_of_lvalue::replay_into (replayer *r)
get_address (playback_location (r, m_loc))); get_address (playback_location (r, m_loc)));
} }
/* Implementation of pure virtual hook recording::rvalue::visit_children
for recording::get_address_of_lvalue. */
void
recording::get_address_of_lvalue::visit_children (rvalue_visitor *v)
{
v->visit (m_lvalue);
}
/* Implementation of recording::memento::make_debug_string for /* Implementation of recording::memento::make_debug_string for
getting the address of an lvalue. */ getting the address of an lvalue. */
......
...@@ -800,6 +800,18 @@ private: ...@@ -800,6 +800,18 @@ private:
fields *m_fields; fields *m_fields;
}; };
/* An abstract base class for operations that visit all rvalues within an
expression tree.
Currently the only implementation is class rvalue_usage_validator within
jit-recording.c. */
class rvalue_visitor
{
public:
virtual ~rvalue_visitor () {}
virtual void visit (rvalue *rvalue) = 0;
};
class rvalue : public memento class rvalue : public memento
{ {
public: public:
...@@ -808,11 +820,14 @@ public: ...@@ -808,11 +820,14 @@ public:
type *type_) type *type_)
: memento (ctxt), : memento (ctxt),
m_loc (loc), m_loc (loc),
m_type (type_) m_type (type_),
m_scope (NULL)
{ {
gcc_assert (type_); gcc_assert (type_);
} }
location * get_loc () const { return m_loc; }
/* Get the recording::type of this rvalue. /* Get the recording::type of this rvalue.
Implements the post-error-checking part of Implements the post-error-checking part of
...@@ -835,9 +850,23 @@ public: ...@@ -835,9 +850,23 @@ public:
lvalue * lvalue *
dereference (location *loc); dereference (location *loc);
void
verify_valid_within_stmt (const char *api_funcname, statement *s);
virtual void visit_children (rvalue_visitor *v) = 0;
void set_scope (function *scope);
function *get_scope () const { return m_scope; }
/* Dynamic cast. */
virtual param *dyn_cast_param () { return NULL; }
protected: protected:
location *m_loc; location *m_loc;
type *m_type; type *m_type;
private:
function *m_scope; /* NULL for globals, non-NULL for locals/params */
}; };
class lvalue : public rvalue class lvalue : public rvalue
...@@ -881,12 +910,16 @@ public: ...@@ -881,12 +910,16 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *) {}
playback::param * playback::param *
playback_param () const playback_param () const
{ {
return static_cast <playback::param *> (m_playback_obj); return static_cast <playback::param *> (m_playback_obj);
} }
param *dyn_cast_param () { return this; }
private: private:
string * make_debug_string () { return m_name; } string * make_debug_string () { return m_name; }
...@@ -925,6 +958,7 @@ public: ...@@ -925,6 +958,7 @@ public:
block* block*
new_block (const char *name); new_block (const char *name);
location *get_loc () const { return m_loc; }
type *get_return_type () const { return m_return_type; } type *get_return_type () const { return m_return_type; }
string * get_name () const { return m_name; } string * get_name () const { return m_name; }
const vec<param *> &get_params () const { return m_params; } const vec<param *> &get_params () const { return m_params; }
...@@ -979,36 +1013,36 @@ public: ...@@ -979,36 +1013,36 @@ public:
bool has_been_terminated () { return m_has_been_terminated; } bool has_been_terminated () { return m_has_been_terminated; }
bool is_reachable () { return m_is_reachable; } bool is_reachable () { return m_is_reachable; }
void statement *
add_eval (location *loc, add_eval (location *loc,
rvalue *rvalue); rvalue *rvalue);
void statement *
add_assignment (location *loc, add_assignment (location *loc,
lvalue *lvalue, lvalue *lvalue,
rvalue *rvalue); rvalue *rvalue);
void statement *
add_assignment_op (location *loc, add_assignment_op (location *loc,
lvalue *lvalue, lvalue *lvalue,
enum gcc_jit_binary_op op, enum gcc_jit_binary_op op,
rvalue *rvalue); rvalue *rvalue);
void statement *
add_comment (location *loc, add_comment (location *loc,
const char *text); const char *text);
void statement *
end_with_conditional (location *loc, end_with_conditional (location *loc,
rvalue *boolval, rvalue *boolval,
block *on_true, block *on_true,
block *on_false); block *on_false);
void statement *
end_with_jump (location *loc, end_with_jump (location *loc,
block *target); block *target);
void statement *
end_with_return (location *loc, end_with_return (location *loc,
rvalue *rvalue); rvalue *rvalue);
...@@ -1063,6 +1097,8 @@ public: ...@@ -1063,6 +1097,8 @@ public:
void replay_into (replayer *); void replay_into (replayer *);
void visit_children (rvalue_visitor *) {}
void write_to_dump (dump &d); void write_to_dump (dump &d);
private: private:
...@@ -1086,6 +1122,8 @@ public: ...@@ -1086,6 +1122,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *) {}
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1104,6 +1142,8 @@ public: ...@@ -1104,6 +1142,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *) {}
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1126,6 +1166,8 @@ public: ...@@ -1126,6 +1166,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1149,6 +1191,8 @@ public: ...@@ -1149,6 +1191,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1173,6 +1217,8 @@ public: ...@@ -1173,6 +1217,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1195,6 +1241,8 @@ public: ...@@ -1195,6 +1241,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1213,6 +1261,8 @@ public: ...@@ -1213,6 +1261,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1232,6 +1282,8 @@ public: ...@@ -1232,6 +1282,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1254,6 +1306,8 @@ public: ...@@ -1254,6 +1306,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1276,6 +1330,8 @@ public: ...@@ -1276,6 +1330,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1298,6 +1354,8 @@ public: ...@@ -1298,6 +1354,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1320,6 +1378,8 @@ public: ...@@ -1320,6 +1378,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1339,6 +1399,8 @@ public: ...@@ -1339,6 +1399,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1358,6 +1420,8 @@ public: ...@@ -1358,6 +1420,8 @@ public:
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *v);
private: private:
string * make_debug_string (); string * make_debug_string ();
...@@ -1371,10 +1435,15 @@ public: ...@@ -1371,10 +1435,15 @@ public:
local (function *func, location *loc, type *type_, string *name) local (function *func, location *loc, type *type_, string *name)
: lvalue (func->m_ctxt, loc, type_), : lvalue (func->m_ctxt, loc, type_),
m_func (func), m_func (func),
m_name (name) {} m_name (name)
{
set_scope (func);
}
void replay_into (replayer *r); void replay_into (replayer *r);
void visit_children (rvalue_visitor *) {}
void write_to_dump (dump &d); void write_to_dump (dump &d);
private: private:
...@@ -1393,6 +1462,7 @@ public: ...@@ -1393,6 +1462,7 @@ public:
void write_to_dump (dump &d); void write_to_dump (dump &d);
block *get_block () const { return m_block; }
location *get_loc () const { return m_loc; } location *get_loc () const { return m_loc; }
protected: protected:
...@@ -1401,8 +1471,6 @@ protected: ...@@ -1401,8 +1471,6 @@ protected:
m_block (b), m_block (b),
m_loc (loc) {} m_loc (loc) {}
block *get_block () const { return m_block; }
playback::location * playback::location *
playback_location (replayer *r) const playback_location (replayer *r) const
{ {
......
...@@ -172,6 +172,16 @@ struct gcc_jit_param : public gcc::jit::recording::param ...@@ -172,6 +172,16 @@ struct gcc_jit_param : public gcc::jit::recording::param
} \ } \
JIT_END_STMT JIT_END_STMT
#define RETURN_VAL_IF_FAIL_PRINTF5(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4) \
JIT_BEGIN_STMT \
if (!(TEST_EXPR)) \
{ \
jit_error ((CTXT), (LOC), "%s: " ERR_FMT, \
__func__, (A0), (A1), (A2), (A3), (A4)); \
return (RETURN_EXPR); \
} \
JIT_END_STMT
#define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \ #define RETURN_VAL_IF_FAIL_PRINTF6(TEST_EXPR, RETURN_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
JIT_BEGIN_STMT \ JIT_BEGIN_STMT \
if (!(TEST_EXPR)) \ if (!(TEST_EXPR)) \
...@@ -197,6 +207,9 @@ struct gcc_jit_param : public gcc::jit::recording::param ...@@ -197,6 +207,9 @@ struct gcc_jit_param : public gcc::jit::recording::param
#define RETURN_NULL_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \ #define RETURN_NULL_IF_FAIL_PRINTF4(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) \
RETURN_VAL_IF_FAIL_PRINTF4 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3) RETURN_VAL_IF_FAIL_PRINTF4 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3)
#define RETURN_NULL_IF_FAIL_PRINTF5(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4) \
RETURN_VAL_IF_FAIL_PRINTF5 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4)
#define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \ #define RETURN_NULL_IF_FAIL_PRINTF6(TEST_EXPR, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) \
RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5) RETURN_VAL_IF_FAIL_PRINTF6 (TEST_EXPR, NULL, CTXT, LOC, ERR_FMT, A0, A1, A2, A3, A4, A5)
...@@ -844,10 +857,23 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt, ...@@ -844,10 +857,23 @@ gcc_jit_context_new_function (gcc_jit_context *ctxt,
ctxt, loc, ctxt, loc,
"NULL params creating function %s", name); "NULL params creating function %s", name);
for (int i = 0; i < num_params; i++) for (int i = 0; i < num_params; i++)
{
RETURN_NULL_IF_FAIL_PRINTF2 ( RETURN_NULL_IF_FAIL_PRINTF2 (
params[i], params[i],
ctxt, loc, ctxt, loc,
"NULL parameter %i creating function %s", i, name); "NULL parameter %i creating function %s", i, name);
RETURN_NULL_IF_FAIL_PRINTF5 (
(NULL == params[i]->get_scope ()),
ctxt, loc,
"parameter %i \"%s\""
" (type: %s)"
" for function %s"
" was already used for function %s",
i, params[i]->get_debug_string (),
params[i]->get_type ()->get_debug_string (),
name,
params[i]->get_scope ()->get_debug_string ());
}
return (gcc_jit_function*) return (gcc_jit_function*)
ctxt->new_function (loc, kind, return_type, name, ctxt->new_function (loc, kind, return_type, name,
...@@ -1800,7 +1826,14 @@ gcc_jit_block_add_eval (gcc_jit_block *block, ...@@ -1800,7 +1826,14 @@ gcc_jit_block_add_eval (gcc_jit_block *block,
/* LOC can be NULL. */ /* LOC can be NULL. */
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
return block->add_eval (loc, rvalue); gcc::jit::recording::statement *stmt = block->add_eval (loc, rvalue);
/* "stmt" should be good enough to be usable in error-messages,
but might still not be compilable; perform some more
error-checking here. We do this here so that the error messages
can contain a stringified version of "stmt", whilst appearing
as close as possible to the point of failure. */
rvalue->verify_valid_within_stmt (__func__, stmt);
} }
/* Public entrypoint. See description in libgccjit.h. /* Public entrypoint. See description in libgccjit.h.
...@@ -1832,7 +1865,15 @@ gcc_jit_block_add_assignment (gcc_jit_block *block, ...@@ -1832,7 +1865,15 @@ gcc_jit_block_add_assignment (gcc_jit_block *block,
rvalue->get_debug_string (), rvalue->get_debug_string (),
rvalue->get_type ()->get_debug_string ()); rvalue->get_type ()->get_debug_string ());
return block->add_assignment (loc, lvalue, rvalue); gcc::jit::recording::statement *stmt = block->add_assignment (loc, lvalue, rvalue);
/* "stmt" should be good enough to be usable in error-messages,
but might still not be compilable; perform some more
error-checking here. We do this here so that the error messages
can contain a stringified version of "stmt", whilst appearing
as close as possible to the point of failure. */
lvalue->verify_valid_within_stmt (__func__, stmt);
rvalue->verify_valid_within_stmt (__func__, stmt);
} }
/* Public entrypoint. See description in libgccjit.h. /* Public entrypoint. See description in libgccjit.h.
...@@ -1860,7 +1901,15 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block, ...@@ -1860,7 +1901,15 @@ gcc_jit_block_add_assignment_op (gcc_jit_block *block,
op); op);
RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue"); RETURN_IF_FAIL (rvalue, ctxt, loc, "NULL rvalue");
return block->add_assignment_op (loc, lvalue, op, rvalue); gcc::jit::recording::statement *stmt = block->add_assignment_op (loc, lvalue, op, rvalue);
/* "stmt" should be good enough to be usable in error-messages,
but might still not be compilable; perform some more
error-checking here. We do this here so that the error messages
can contain a stringified version of "stmt", whilst appearing
as close as possible to the point of failure. */
lvalue->verify_valid_within_stmt (__func__, stmt);
rvalue->verify_valid_within_stmt (__func__, stmt);
} }
/* Internal helper function for determining if rvalue BOOLVAL is of /* Internal helper function for determining if rvalue BOOLVAL is of
...@@ -1921,7 +1970,14 @@ gcc_jit_block_end_with_conditional (gcc_jit_block *block, ...@@ -1921,7 +1970,14 @@ gcc_jit_block_end_with_conditional (gcc_jit_block *block,
on_false->get_debug_string (), on_false->get_debug_string (),
on_false->get_function ()->get_debug_string ()); on_false->get_function ()->get_debug_string ());
return block->end_with_conditional (loc, boolval, on_true, on_false); gcc::jit::recording::statement *stmt = block->end_with_conditional (loc, boolval, on_true, on_false);
/* "stmt" should be good enough to be usable in error-messages,
but might still not be compilable; perform some more
error-checking here. We do this here so that the error messages
can contain a stringified version of "stmt", whilst appearing
as close as possible to the point of failure. */
boolval->verify_valid_within_stmt (__func__, stmt);
} }
/* Public entrypoint. See description in libgccjit.h. /* Public entrypoint. See description in libgccjit.h.
...@@ -2003,7 +2059,14 @@ gcc_jit_block_end_with_return (gcc_jit_block *block, ...@@ -2003,7 +2059,14 @@ gcc_jit_block_end_with_return (gcc_jit_block *block,
func->get_debug_string (), func->get_debug_string (),
func->get_return_type ()->get_debug_string ()); func->get_return_type ()->get_debug_string ());
return block->end_with_return (loc, rvalue); gcc::jit::recording::statement *stmt = block->end_with_return (loc, rvalue);
/* "stmt" should be good enough to be usable in error-messages,
but might still not be compilable; perform some more
error-checking here. We do this here so that the error messages
can contain a stringified version of "stmt", whilst appearing
as close as possible to the point of failure. */
rvalue->verify_valid_within_stmt (__func__, stmt);
} }
/* Public entrypoint. See description in libgccjit.h. /* Public entrypoint. See description in libgccjit.h.
...@@ -2029,7 +2092,7 @@ gcc_jit_block_end_with_void_return (gcc_jit_block *block, ...@@ -2029,7 +2092,7 @@ gcc_jit_block_end_with_void_return (gcc_jit_block *block,
func->get_debug_string (), func->get_debug_string (),
func->get_return_type ()->get_debug_string ()); func->get_return_type ()->get_debug_string ());
return block->end_with_return (loc, NULL); block->end_with_return (loc, NULL);
} }
/********************************************************************** /**********************************************************************
......
2015-01-12 David Malcolm <dmalcolm@redhat.com>
* jit.dg/test-error-local-used-from-other-function.c: New test
case.
* jit.dg/test-error-param-reuse.c: New test case.
* jit.dg/test-error-param-sharing.c: New test case.
* jit.dg/test-error-param-used-from-other-function.c: New test
case.
* jit.dg/test-error-param-used-without-a-function.c: New test
case.
2015-01-12 Jakub Jelinek <jakub@redhat.com> 2015-01-12 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/64563 PR tree-optimization/64563
......
#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:
void
fn_one ()
{
int i;
}
int
fn_two ()
{
return i;
}
and verify that the API complains about the use of the local
from the other function. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_function *fn_one =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"fn_one",
0, NULL,
0);
gcc_jit_lvalue *local =
gcc_jit_function_new_local (fn_one, NULL, int_type, "i");
gcc_jit_function *fn_two =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"fn_two",
0, NULL,
0);
gcc_jit_block *block = gcc_jit_function_new_block (fn_two, NULL);
/* "return i;", using local i from the wrong function. */
gcc_jit_block_end_with_return (block,
NULL,
gcc_jit_lvalue_as_rvalue (local));
}
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_block_end_with_return:"
" rvalue i (type: int)"
" has scope limited to function fn_one"
" but was used within function fn_two"
" (in statement: return i;)"));
}
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Verify that we get an error (rather than a crash)
if the client code reuses a gcc_jit_param * within
a function. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Create a param. */
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
/* Try to use it twice when creating "fn". */
gcc_jit_param *params[2];
params[0] = param;
params[1] = param;
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_IMPORTED,
void_type,
"fn",
2, params,
0);
}
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_function:"
" parameter i (type: int)"
" is used more than once when creating function"
" fn"))
}
#include <stdlib.h>
#include <stdio.h>
#include "libgccjit.h"
#include "harness.h"
#ifdef __cplusplus
extern "C" {
#endif
extern void
called_function (void *ptr);
#ifdef __cplusplus
}
#endif
void
create_code (gcc_jit_context *ctxt, void *user_data)
{
/* Verify that we get an error (rather than a crash)
if the client code reuses a gcc_jit_param * for
two different functions. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
/* Create a param. */
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
/* Try to use it for two different functions. */
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"fn_one",
1, &param,
0);
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"fn_two",
1, &param,
0);
}
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_function:"
" parameter 0 \"i\" (type: int)"
" for function fn_two"
" was already used for function fn_one"))
}
#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:
void
fn_one (int i)
{
}
int
fn_two ()
{
return i * 2;
}
and verify that the API complains about the use of the param
from the other function. */
gcc_jit_type *void_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
void_type,
"fn_one",
1, &param,
0);
gcc_jit_function *fn_two =
gcc_jit_context_new_function (ctxt, NULL,
GCC_JIT_FUNCTION_EXPORTED,
int_type,
"fn_two",
0, NULL,
0);
gcc_jit_block *block = gcc_jit_function_new_block (fn_two, NULL);
/* "return i * 2;", using param i from the wrong function. */
gcc_jit_block_end_with_return (
block,
NULL,
gcc_jit_context_new_binary_op (
ctxt, NULL,
GCC_JIT_BINARY_OP_MULT,
int_type,
gcc_jit_param_as_rvalue (param),
gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 2)));
}
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_block_end_with_return:"
" rvalue i (type: int)"
" has scope limited to function fn_one"
" but was used within function fn_two"
" (in statement: return i * (int)2;)"));
}
#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 ()
{
return i;
}
where "i" is a param that isn't associated with any function,
and verify that the API complains. */
gcc_jit_type *int_type =
gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
gcc_jit_param *param =
gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
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_block *block = gcc_jit_function_new_block (test_fn, NULL);
/* "return i;", using param i from the wrong function. */
gcc_jit_block_end_with_return (block,
NULL,
gcc_jit_param_as_rvalue (param));
}
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_block_end_with_return:"
" param i (type: int)"
" was used within function test_fn"
" (in statement: return i;)"
" but is not associated with any function"))
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment