Use exceptions in the C++ wrapper API

Error-handling in the C API works by returning NULL when an error
occurs (and setting an error on the context), and handling NULL inputs
by immediately returning NULL (setting another error).  Hence the
presence of a NULL indicates some kind of error has occurred.

Update the C++ API to check for NULL pointers in the constructors for
the various wrappers classes, throwing an exception if one if passed in.

Hence any erroneous use of the API (e.g. type-mismatches) will lead to
immediate failure, rather than the previous behavior of a flurry of
text on stderr.

Also, make gccjit::context::m_inner private.

gcc/jit/
	* libgccjit++.h (gccjit::error): New class, for exceptions.
	(gccjit::context::get_inner_context): New accessor, so that we
	can...
	(gccjit::context::m_inner_ctxt): Make private.
	(gccjit::context::context): Throw a gccjit::error if a NULL
	context is passed in.
	(gccjit::context::compile): Throw a gccjit::error if a NULL
	result is returned from the C API, which indicates an error.
	(gccjit::object::object): Throw a gccjit::error if a NULL
	object is passed in, since that indicates that an error has
	occurred.
	(gccjit::location::location): In the default ctor, call the
	base class default ctor rather than passing in a NULL to the
	single-argument ctor, since the latter now indicates an error
	has occurred at the C API level.
	(gccjit::field::field): Likewise.
	(gccjit::type::type): Likewise.
	(gccjit::function::function): Likewise.
	(gccjit::block::block): Likewise.
	(gccjit::rvalue::rvalue): Likewise.
Make various C++ wrapper methods const

gcc/jit/
	* libgccjit++.h (gccjit::context::new_rvalue): Make these
	methods const.
	(gccjit::context::zero): Likewise.
	(gccjit::context::one): Likewise.
	(gccjit::function::get_param): Likewise.
add missing ChangeLog.jit entry
Fix global state init_p within ipa_init

Attempting to repeatedly compile with optimizations on within one
process would, under some circumstances, lead to a segfault the second
time in, here:

 #0  splay_tree_delete (sp=0x0) at ../../src/libiberty/splay-tree.c:353
 #1  0x00007ffff77f104f in propagate () at ../../src/gcc/ipa-reference.c:878
 #2  0x00007ffff77f1d23 in (anonymous namespace)::pass_ipa_reference::execute
	(this=0x72f5d0) at ../../src/gcc/ipa-reference.c:1191
 #3  0x00007ffff6fc5237 in execute_one_pass (pass=0x72f5d0) at
	../../src/gcc/passes.c:2216
 #4  0x00007ffff6fc6044 in execute_ipa_pass_list (pass=0x72f5d0) at
	../../src/gcc/passes.c:2580
 #5  0x00007ffff6c93d5f in ipa_passes () at ../../src/gcc/cgraphunit.c:2027

The crash occurred here:
 #1  0x00007ffff77f104f in propagate () at ../../src/gcc/ipa-reference.c:878
 878	    splay_tree_delete (reference_vars_to_consider);
 (gdb) p reference_vars_to_consider
 $10 = (splay_tree) 0x0

This tended to occur when working with functions intended to be inlined.

Debuggging indicated that the root-cause was the "init_p" flag within
ipa_init: it is static, presumably to allow idempotent initialization.
However, there is also cleanup, so that the 2nd time in, ipa-reference.c
is working with post-clean up state, failing to rebuild its data structures
(e.g. a NULL for "reference_vars_to_consider").

Hence this patches changes ipa initialization from being idempotent within
the lifetime of the process to being idempotent within one invocation of
toplev_main, by moving it from static in function scope to *file* scope,
adding a reset of the flag to toplev_finalize.

[That said, I *think* ipa_init is only called at most once per invocation
of toplev_main.]

Doing so allows the optimizer to inline functions in repeated invocations
of the compiler within one process.
[...provided debuginfo generation is disabled.  In this latter case, with
GCC_JIT_BOOL_OPTION_DEBUGINFO, the equivalent of -g, I'm currently running
into what I take to be a separate segfault in dwarf2out.c the second time
in.  I haven't tracked this other one down yet.]

gcc/
	* ipa-reference.c (ipa_init): Move static bool init_p from here
	to...
	(ipa_init_p): New file-scope variable, so that it can be reset
	when repeatedly invoking the compiler within one process by...
	(ipa_reference_c_finalize): New function.
	* ipa-reference.h (ipa_reference_c_finalize): New.
	* toplev.c (toplev_finalize): Invoke new function
	ipa_reference_c_finalize.
Cleanup base_types

I tracked down the crash in dwarf2out.c mentioned in the commit message
for 6e624036e3f47c6ca4ae2e99974b74aa29f11eca:
"base_types" wasn't being flushed between invocations, leading to it
containing garbage that might be collected (it's not GTY-labelled), and
duplicate copies of types that appeared to violate reference-counting
checking in the DWARF string pruner, due to multiple copies of the
string "__unknown__".

Release it.

With this commit, *almost* all of the test suite runs successfully at
optimization level 3, the exception being a crash in test-linked-list.c
that I've yet to figure out.

gcc/
	* dwarf2out.c (dwarf2out_c_finalize): Release base_types.
Fix state issue in gcse.c

Turning optimizations up from 0 to 3 showed a segfault on the 2nd
iteration of test-linked-list.c in get_data_from_adhoc_loc whilst
garbage-collecting.

Investigation revealed the issue to be a CFG from the previous compile
being kept alive by this GC root in gcse.c:
	  static GTY(()) rtx test_insn;

This wouldn't it itself be an issue, but one (or more) of the edges had:

  (gdb) p /x e->goto_locus
  $9 = 0x80000000

and was thus treated as an ADHOC_LOC.  Hence, this line in the edge_def's
gt_ggc_mx routine:

  8313	  tree block = LOCATION_BLOCK (e->goto_locus);

led to a call (via LOCATION_BLOCK) to get_data_from_adhoc_loc:

152	void *
153	get_data_from_adhoc_loc (struct line_maps *set, source_location loc)
154	{
155	  linemap_assert (IS_ADHOC_LOC (loc));
156	  return set->location_adhoc_data_map.data[loc & MAX_SOURCE_LOCATION].data;
157	}

but at this point, the ad-hoc location data from the previous in-process
compile no longer makes sense, and, with:
  (gdb) p set->location_adhoc_data_map
  $5 = {htab = 0x60fbb0, curr_loc = 0, allocated = 0, data = 0x0}

the read though the NULL "data" segfaults.

gcse.c appears to create test_insn on-demand as part of the implementation of
can_assign_to_reg_without_clobbers_p.

Hence it seems to make most sense to simply clear test_insn in toplev_finalize,
which this commit does.

With this, the whole test suite now runs successfully with optimizations
on, so also turn this up (in harness.h) from 0 to 3.

gcc/
	* gcse.c (gcse_c_finalize): New, to clear test_insn between
	in-process compiles.
	* gcse.h (gcse_c_finalize): New.
	* toplev.c: Include "gcse.h" so that we can...
	(toplev_finalize): Call gcse_c_finalize.

gcc/testsuite/
	* jit.dg/harness.h (set_options): Increase optimization level from
	0 to 3.
Include locations in error reports where available

Update the error-handling machinery to pass around (recording::location *)
values (aka a gcc_jit_location *), printing them when reporting errors,
where available (they can be NULL).

Also, in gcc::jit::recording::context::errors_occurred, consider
errors as having occurred if they occured on a parent (or ancestor)
context.

gcc/jit/
	* 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.
	(gcc::jit::recording::context::set_bool_option): Likewise.
	(gcc::jit::playback::context::compile): Likewise.
	(gcc::jit::recording::context::add_error): Add recording::location
	param.
	(gcc::jit::recording::context::add_error_va): Likewise; print it
	when present; add "error: " to stderr messages.
	(gcc::jit::recording::location::replay_into): Provide
	recording::location to the playback::location.

	(gcc::jit::recording::function::validate): Add locations to the
	add_error invocations.
	(gcc::jit::recording::block::validate): Likewise.
	(gcc::jit::playback::context::get_type): Likewise.
	(gcc::jit::playback::context::new_unary_op): Likewise.
	(gcc::jit::playback::context::new_binary_op): Likewise.
	(gcc::jit::playback::context::new_comparison): Likewise.

	(gcc::jit::recording::block::get_loc): New.
	(gcc::jit::recording::block::get_first_statement): New.

	(gcc::jit::playback::context::build_cast): Pass in higher-level
	arguments in the hope of eventually providing better error
	messages when a cast isn't possible.
	(gcc::jit::playback::context::new_cast): As above.

	(gcc::jit::playback::context::add_error): Add playback::location
	parameter, using it to provide the corresponding
	recording::location (if any) when reporting the error to the
	recording::context.
	(gcc::jit::playback::context::add_error_va): Likewise.
	(gcc::jit::playback::context::new_location): Likewise.
	(gcc::jit::playback::source_line::get_location): Likewise.
	(gcc::jit::playback::location::location): Likewise.

	* internal-api.h (gcc::jit::recording::context::add_error): Add
	recording::location param.
	(gcc::jit::recording::context::add_error_va): Likewise.

	(gcc::jit::recording::context::errors_occurred): Also consider
	errors that occur on a parent or ancestor context, recursively.

	(gcc::jit::recording::block::get_loc): New.
	(gcc::jit::recording::block::get_first_statement): New.
	(gcc::jit::recording::statement::get_loc): New.

	(gcc::jit::playback::context::new_location): Add recording::location
	parameter.

	(gcc::jit::playback::context::add_error): Add playback::location
	parameter.
	(gcc::jit::playback::context::add_error_va): Likewise.

	(gcc::jit::playback::context::build_cast): Pass in higher-level
	arguments in the hope of eventually providing better error
	messages when a cast isn't possible.

	(gcc::jit::playback::source_line::get_location): Add
	recording::location parameter.
	(gcc::jit::playback::location::location): Likewise.
	(gcc::jit::playback::location::get_recording_loc): New.
	(gcc::jit::playback::location::m_recording_loc): New.

	* jit-builtins.c (gcc::jit::builtins_manager::get_builtin_function):
	Provide NULL recording::location to add_error.
	(gcc::jit::builtins_manager::make_primitive_type): Likewise.

	* libgccjit.c (RETURN_VAL_IF_FAIL): Add location argument.
	(RETURN_VAL_IF_FAIL_PRINTF1): Likewise.
	(RETURN_VAL_IF_FAIL_PRINTF2): Likewise.
	(RETURN_VAL_IF_FAIL_PRINTF3): Likewise.
	(RETURN_VAL_IF_FAIL_PRINTF4): Likewise.
	(RETURN_VAL_IF_FAIL_PRINTF6): Likewise.
	(RETURN_NULL_IF_FAIL): Likewise.
	(RETURN_NULL_IF_FAIL_PRINTF1): Likewise.
	(RETURN_NULL_IF_FAIL_PRINTF2): Likewise.
	(RETURN_NULL_IF_FAIL_PRINTF3): Likewise.
	(RETURN_NULL_IF_FAIL_PRINTF4): Likewise.
	(RETURN_NULL_IF_FAIL_PRINTF6): Likewise.
	(RETURN_IF_FAIL): Likewise.
	(RETURN_IF_FAIL_PRINTF1): Likewise.
	(RETURN_IF_FAIL_PRINTF2): Likewise.
	(RETURN_IF_FAIL_PRINTF4): Likewise.
	(RETURN_IF_NOT_VALID_BLOCK): Likewise.
	(RETURN_NULL_IF_NOT_VALID_BLOCK): Likewise.

	(jit_error): Likewise.

	(gcc_jit_location_as_object): Provided location argument to
	error-handling macros.
	(gcc_jit_type_as_object): Likewise.
	(gcc_jit_context_get_type): Likewise.
	(gcc_jit_context_get_int_type): Likewise.
	(gcc_jit_type_get_pointer): Likewise.
	(gcc_jit_type_get_const): Likewise.
	(gcc_jit_type_get_volatile): Likewise.
	(gcc_jit_context_new_array_type): Likewise.
	(gcc_jit_context_new_field): Likewise.
	(gcc_jit_context_new_struct_type): Likewise.
	(gcc_jit_context_new_opaque_struct): Likewise.
	(gcc_jit_struct_as_type): Likewise.
	(gcc_jit_struct_set_fields): Likewise.
	(gcc_jit_context_new_param): Likewise.
	(gcc_jit_param_as_object): Likewise.
	(gcc_jit_param_as_lvalue): Likewise.
	(gcc_jit_param_as_rvalue): Likewise.
	(gcc_jit_context_new_function): Likewise.
	(gcc_jit_context_get_builtin_function): Likewise.
	(gcc_jit_function_as_object): Likewise.
	(gcc_jit_function_get_param): Likewise.
	(gcc_jit_function_dump_to_dot): Likewise.
	(gcc_jit_function_new_block): Likewise.
	(gcc_jit_block_as_object): Likewise.
	(gcc_jit_block_get_function): Likewise.
	(gcc_jit_context_new_global): Likewise.
	(gcc_jit_lvalue_as_object): Likewise.
	(gcc_jit_lvalue_as_rvalue): Likewise.
	(gcc_jit_rvalue_as_object): Likewise.
	(gcc_jit_rvalue_get_type): Likewise.
	(gcc_jit_context_new_rvalue_from_int): Likewise.
	(gcc_jit_context_zero): Likewise.
	(gcc_jit_context_one): Likewise.
	(gcc_jit_context_new_rvalue_from_double): Likewise.
	(gcc_jit_context_new_rvalue_from_ptr): Likewise.
	(gcc_jit_context_null): Likewise.
	(gcc_jit_context_new_string_literal): Likewise.
	(gcc_jit_context_new_unary_op): Likewise.
	(gcc_jit_context_new_binary_op): Likewise.
	(gcc_jit_context_new_comparison): Likewise.
	(gcc_jit_context_new_call): Likewise.
	(gcc_jit_context_new_cast): Likewise.
	(gcc_jit_context_new_array_access): Likewise.
	(gcc_jit_object_get_context): Likewise.
	(gcc_jit_object_get_debug_string): Likewise.
	(gcc_jit_lvalue_access_field): Likewise.
	(gcc_jit_rvalue_access_field): Likewise.
	(gcc_jit_rvalue_dereference_field): Likewise.
	(gcc_jit_rvalue_dereference_field): Likewise.
	(gcc_jit_rvalue_dereference): Likewise.
	(gcc_jit_lvalue_get_address): Likewise.
	(gcc_jit_function_new_local): Likewise.
	(gcc_jit_block_add_eval): Likewise.
	(gcc_jit_block_add_assignment): Likewise.
	(gcc_jit_block_add_assignment_op): Likewise.
	(gcc_jit_block_end_with_conditional): Likewise.
	(gcc_jit_block_add_comment): Likewise.
	(gcc_jit_block_end_with_jump): Likewise.
	(gcc_jit_block_end_with_return): Likewise.
	(gcc_jit_block_end_with_void_return): Likewise.
	(gcc_jit_context_set_str_option): Likewise.
	(gcc_jit_context_set_int_option): Likewise.
	(gcc_jit_context_set_bool_option): Likewise.
	(gcc_jit_context_compile): Likewise.
	(gcc_jit_context_dump_to_file): Likewise.
	(gcc_jit_context_get_first_error): Likewise.
	(gcc_jit_result_get_code): Likewise.
	(gcc_jit_result_get_code): Likewise.
	(gcc_jit_result_release): Likewise.
Add type-checking to gcc_jit_context_new_cast

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.
Support array to pointer conversions

gcc/jit/
	* libgccjit.c (is_valid_cast): Permit casts between pointer types.

	* internal-api.c (convert): Report more information if this ever
	occurs, and make the error occur on the playback context, so that
	it makes the gcc_jit_result be NULL.
	(gcc::jit::playback::context::build_cast): Handle pointers.  Report
	more information if an unhandlable cast reaches here.

gcc/testsuite/
	* jit.dg/test-expressions.c (called_pointer_checking_function): New.
	(make_tests_of_casts): Add test of casting from array to pointer.
	(verify_casts): Likewise.
Add missing tests to test-combination.c

gcc/testsuite/
	* jit.dg/test-combination.c: Add test-arrays.c and test-volatile.c.
	Add comment about test-error-*.c.  Remove comment about
	test-failure.c, which was removed in
	96b218c9a1d5f39fb649e02c0e77586b180e8516.
	(create_code): Call into test-arrays.c and test-volatile.c.
	(verify_code): Likewise.
Tighten up the distinction between pointers and arrays

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
Avoid shadowing progname global

gcc/jit/
	* internal-api.c (gcc::jit::recording::context::add_error_va):
	Rename local "progname" to "ctxt_progname" to avoid shadowing
	the related global, for clarity.
	(gcc::jit::playback::context::compile): Likewise.
introduce class toplev

This patch introduces a new "class toplev" and changes toplev_main and
toplev_finalize to be methods of this class.  Additionally, now the
timevars are automatically stopped when the object is destroyed.  This
cleans up "compile" a bit and makes it simpler to reuse the toplev
logic in other code.
introduce auto_timevar

This introduces a new auto_timevar class.  It pushes a given timevar
in its constructor, and pops it in the destructor, giving a much
simpler way to use timevars in the typical case where they can be
scoped.
initialize input_location

This patch initializes input_location at the same spot where the line
table is initialized.  Without this, it's possible to crash when
emitting a diagnostic in a reinvocation of the compiler, because
input_location refers to a location that is no longer valid.