https://gcc.gnu.org/g:7bb75a5edc1b3c90500e2a78124feac7beefacad
commit r15-4933-g7bb75a5edc1b3c90500e2a78124feac7beefacad Author: Antoni Boucher <boua...@zoho.com> Date: Tue May 24 17:45:01 2022 -0400 libgccjit: Add gcc_jit_global_set_readonly gcc/jit/ChangeLog: * docs/topics/compatibility.rst (LIBGCCJIT_ABI_29): New ABI tag. * docs/topics/expressions.rst: Document gcc_jit_global_set_readonly. * jit-playback.cc (global_new_decl, new_global, new_global_initialized): New parameter readonly. * jit-playback.h (global_new_decl, new_global, new_global_initialized): New parameter readonly. * jit-recording.cc (recording::global::replay_into): Use m_readonly. (recording::global::write_reproducer): Dump reproducer for gcc_jit_global_set_readonly. * jit-recording.h (get_readonly, set_readonly): New methods. (m_readonly): New attribute. * libgccjit.cc (gcc_jit_global_set_readonly): New function. (gcc_jit_block_add_assignment): Check that we don't assign to a readonly variable. * libgccjit.h (gcc_jit_global_set_readonly): New function. (LIBGCCJIT_HAVE_gcc_jit_global_set_readonly): New define. * libgccjit.map: New function. gcc/testsuite/ChangeLog: * jit.dg/all-non-failing-tests.h: Mention test-readonly.c. * jit.dg/test-error-assign-readonly.c: New test. * jit.dg/test-readonly.c: New test. Diff: --- gcc/jit/docs/topics/compatibility.rst | 7 +++ gcc/jit/docs/topics/expressions.rst | 12 +++++ gcc/jit/jit-playback.cc | 15 +++--- gcc/jit/jit-playback.h | 9 ++-- gcc/jit/jit-recording.cc | 9 +++- gcc/jit/jit-recording.h | 11 ++++ gcc/jit/libgccjit.cc | 22 ++++++++ gcc/jit/libgccjit.h | 5 ++ gcc/jit/libgccjit.map | 5 ++ gcc/testsuite/jit.dg/all-non-failing-tests.h | 3 ++ gcc/testsuite/jit.dg/test-error-assign-readonly.c | 62 +++++++++++++++++++++++ gcc/testsuite/jit.dg/test-readonly.c | 38 ++++++++++++++ 12 files changed, 187 insertions(+), 11 deletions(-) diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst index 92c3ed24c892..96adc03fed4d 100644 --- a/gcc/jit/docs/topics/compatibility.rst +++ b/gcc/jit/docs/topics/compatibility.rst @@ -404,3 +404,10 @@ on functions and variables: -------------------- ``LIBGCCJIT_ABI_28`` covers the addition of :func:`gcc_jit_context_new_alignof` + +.. _LIBGCCJIT_ABI_29: + +``LIBGCCJIT_ABI_29`` +-------------------- +``LIBGCCJIT_ABI_29`` covers the addition of +:func:`gcc_jit_global_set_readonly` diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst index 5734f0e5f7e5..2aabbb82a6bc 100644 --- a/gcc/jit/docs/topics/expressions.rst +++ b/gcc/jit/docs/topics/expressions.rst @@ -989,6 +989,18 @@ Variables #ifdef LIBGCCJIT_HAVE_ATTRIBUTES +.. function:: void\ + gcc_jit_global_set_readonly (gcc_jit_lvalue *global) + + Set the global variable as read-only, meaning you cannot assign to this variable. + + This entrypoint was added in :ref:`LIBGCCJIT_ABI_29`; you can test for its + presence using: + + .. code-block:: c + + #ifdef LIBGCCJIT_HAVE_gcc_jit_global_set_readonly + Working with pointers, structs and unions ----------------------------------------- diff --git a/gcc/jit/jit-playback.cc b/gcc/jit/jit-playback.cc index 8dd77e4d5871..f0f01648ac19 100644 --- a/gcc/jit/jit-playback.cc +++ b/gcc/jit/jit-playback.cc @@ -723,7 +723,8 @@ global_new_decl (location *loc, const char *name, enum global_var_flags flags, const std::vector<std::pair<gcc_jit_variable_attribute, - std::string>> &attributes) + std::string>> &attributes, + bool readonly) { gcc_assert (type); gcc_assert (name); @@ -762,7 +763,7 @@ global_new_decl (location *loc, break; } - if (TYPE_READONLY (type_tree)) + if (TYPE_READONLY (type_tree) || readonly) TREE_READONLY (inner) = 1; if (loc) @@ -815,10 +816,11 @@ new_global (location *loc, const char *name, enum global_var_flags flags, const std::vector<std::pair<gcc_jit_variable_attribute, - std::string>> &attributes) + std::string>> &attributes, + bool readonly) { tree inner = - global_new_decl (loc, kind, type, name, flags, attributes); + global_new_decl (loc, kind, type, name, flags, attributes, readonly); return global_finalize_lvalue (inner); } @@ -965,9 +967,10 @@ new_global_initialized (location *loc, const char *name, enum global_var_flags flags, const std::vector<std::pair<gcc_jit_variable_attribute, - std::string>> &attributes) + std::string>> &attributes, + bool readonly) { - tree inner = global_new_decl (loc, kind, type, name, flags, attributes); + tree inner = global_new_decl (loc, kind, type, name, flags, attributes, readonly); vec<constructor_elt, va_gc> *constructor_elements = NULL; diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h index 77ae2add4790..212f0b2662df 100644 --- a/gcc/jit/jit-playback.h +++ b/gcc/jit/jit-playback.h @@ -130,7 +130,8 @@ public: const char *name, enum global_var_flags flags, const std::vector<std::pair<gcc_jit_variable_attribute, - std::string>> &attributes); + std::string>> &attributes, + bool readonly); lvalue * new_global_initialized (location *loc, @@ -144,7 +145,8 @@ public: const std::vector<std::pair< gcc_jit_variable_attribute, std::string>> - &attributes); + &attributes, + bool readonly); rvalue * new_ctor (location *log, @@ -337,7 +339,8 @@ private: const char *name, enum global_var_flags flags, const std::vector<std::pair<gcc_jit_variable_attribute, - std::string>> &attributes); + std::string>> &attributes, + bool readonly); lvalue * global_finalize_lvalue (tree inner); diff --git a/gcc/jit/jit-recording.cc b/gcc/jit/jit-recording.cc index 83a36db653de..c6b9b3c54bf9 100644 --- a/gcc/jit/jit-recording.cc +++ b/gcc/jit/jit-recording.cc @@ -5051,13 +5051,15 @@ recording::global::replay_into (replayer *r) m_initializer, playback_string (m_name), m_flags, - m_string_attributes) + m_string_attributes, + m_readonly) : r->new_global (playback_location (r, m_loc), m_kind, m_type->playback_type (), playback_string (m_name), m_flags, - m_string_attributes); + m_string_attributes, + m_readonly); if (m_tls_model != GCC_JIT_TLS_MODEL_NONE) global->set_tls_model (recording::tls_models[m_tls_model]); @@ -5234,6 +5236,9 @@ recording::global::write_reproducer (reproducer &r) gcc_jit_variable_attribute_enum_strings[std::get<0>(attribute)], std::get<1>(attribute).c_str()); + if (m_readonly) + r.write (" gcc_jit_global_set_readonly (%s /* gcc_jit_lvalue *lvalue */);\n", + id); if (m_initializer) switch (m_type->dereference ()->get_size ()) diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h index abd4f6f8bb33..07fdcb907734 100644 --- a/gcc/jit/jit-recording.h +++ b/gcc/jit/jit-recording.h @@ -1284,6 +1284,16 @@ public: void add_string_attribute (gcc_jit_variable_attribute attribute, const char* value); + bool get_readonly () const + { + return m_readonly; + } + + void set_readonly () + { + m_readonly = true; + } + virtual const char *access_as_lvalue (reproducer &r); virtual bool is_global () const { return false; } virtual bool is_local () const { return false; } @@ -1300,6 +1310,7 @@ protected: unsigned m_alignment; std::vector<std::pair<gcc_jit_variable_attribute, std::string>> m_string_attributes; + bool m_readonly = false; }; class param : public lvalue diff --git a/gcc/jit/libgccjit.cc b/gcc/jit/libgccjit.cc index eb38da91df1e..cc36ae964332 100644 --- a/gcc/jit/libgccjit.cc +++ b/gcc/jit/libgccjit.cc @@ -1868,6 +1868,23 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, return global; } +/* Public entrypoint. See description in libgccjit.h. + + After error-checking, the real work is done by the + gcc::jit::recording::global::set_readonly method, in + jit-recording.cc. */ + +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global) +{ + RETURN_IF_FAIL (global, NULL, NULL, "NULL global"); + RETURN_IF_FAIL_PRINTF1 (global->is_global (), NULL, NULL, + "lvalue \"%s\" not a global", + global->get_debug_string ()); + + global->set_readonly (); +} + /* Public entrypoint. See description in libgccjit.h. After error-checking, this calls the trivial @@ -2880,6 +2897,11 @@ gcc_jit_block_add_assignment (gcc_jit_block *block, lvalue->get_type ()->get_debug_string (), rvalue->get_debug_string (), rvalue->get_type ()->get_debug_string ()); + RETURN_IF_FAIL_PRINTF1 ( + !lvalue->get_readonly (), + ctxt, loc, + "cannot assign to readonly variable: %s", + lvalue->get_debug_string ()); gcc::jit::recording::statement *stmt = block->add_assignment (loc, lvalue, rvalue); diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h index 03bfc0f58a53..b1b727744984 100644 --- a/gcc/jit/libgccjit.h +++ b/gcc/jit/libgccjit.h @@ -1052,6 +1052,11 @@ gcc_jit_global_set_initializer (gcc_jit_lvalue *global, const void *blob, size_t num_bytes); +extern void +gcc_jit_global_set_readonly (gcc_jit_lvalue *global); + +#define LIBGCCJIT_HAVE_gcc_jit_global_set_readonly + /* Upcasting. */ extern gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue *lvalue); diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map index b02783ebfb24..26934ddf8a0e 100644 --- a/gcc/jit/libgccjit.map +++ b/gcc/jit/libgccjit.map @@ -294,3 +294,8 @@ LIBGCCJIT_ABI_28 { global: gcc_jit_context_new_alignof; } LIBGCCJIT_ABI_27; + +LIBGCCJIT_ABI_29 { + global: + gcc_jit_global_set_readonly; +} LIBGCCJIT_ABI_28; diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h index 75721329ab53..dfb4dfa98db9 100644 --- a/gcc/testsuite/jit.dg/all-non-failing-tests.h +++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h @@ -351,6 +351,9 @@ #undef create_code #undef verify_code +/* test-readonly.c: This can't be in the testcases array as it + is target-specific. */ + /* test-restrict.c: This can't be in the testcases array as it needs the `-O3` flag. */ diff --git a/gcc/testsuite/jit.dg/test-error-assign-readonly.c b/gcc/testsuite/jit.dg/test-error-assign-readonly.c new file mode 100644 index 000000000000..628bdb86d1cf --- /dev/null +++ b/gcc/testsuite/jit.dg/test-error-assign-readonly.c @@ -0,0 +1,62 @@ +#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: + + const long integer = 10; + + void + test_fn () + { + integer = 12; + } + + and verify that the API complains about assigning to a read-only + variable. + */ + gcc_jit_type *void_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID); + gcc_jit_type *long_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_LONG); + + gcc_jit_function *func = + gcc_jit_context_new_function (ctxt, NULL, + GCC_JIT_FUNCTION_EXPORTED, + void_type, + "test_fn", + 0, NULL, + 0); + gcc_jit_block *initial = + gcc_jit_function_new_block (func, "initial"); + + gcc_jit_lvalue *integer = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, long_type, "integer"); + + gcc_jit_rvalue *ten = gcc_jit_context_new_rvalue_from_int (ctxt, long_type, 10); + gcc_jit_global_set_initializer_rvalue (integer, ten); + gcc_jit_global_set_readonly(integer); + + gcc_jit_rvalue *twelve = gcc_jit_context_new_rvalue_from_int (ctxt, long_type, 12); + gcc_jit_block_add_assignment(initial, NULL, integer, twelve); + + gcc_jit_block_end_with_void_return (initial, NULL); +} + +void +verify_code (gcc_jit_context *ctxt, gcc_jit_result *result) +{ + CHECK_VALUE (result, NULL); + + /* Verify that the correct error messages were emitted. */ + CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt), + "gcc_jit_block_add_assignment:" + " cannot assign to readonly variable: integer"); +} diff --git a/gcc/testsuite/jit.dg/test-readonly.c b/gcc/testsuite/jit.dg/test-readonly.c new file mode 100644 index 000000000000..554fa0bad78c --- /dev/null +++ b/gcc/testsuite/jit.dg/test-readonly.c @@ -0,0 +1,38 @@ +/* { dg-do compile { target x86_64-*-* } } */ + +#include <stdlib.h> +#include <stdio.h> + +#include "libgccjit.h" + +/* We don't want set_options() in harness.h to set -O3 so our little local + is optimized away. */ +#define TEST_ESCHEWS_SET_OPTIONS +static void set_options (gcc_jit_context *ctxt, const char *argv0) +{ +} + +#define TEST_COMPILING_TO_FILE +#define OUTPUT_KIND GCC_JIT_OUTPUT_KIND_ASSEMBLER +#define OUTPUT_FILENAME "output-of-test-readonly.c.s" +#include "harness.h" + +void +create_code (gcc_jit_context *ctxt, void *user_data) +{ + /* Let's try to inject the equivalent of: + const int foo; + */ + gcc_jit_type *int_type = + gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT); + gcc_jit_lvalue *foo = + gcc_jit_context_new_global ( + ctxt, NULL, GCC_JIT_GLOBAL_EXPORTED, int_type, "foo"); + + gcc_jit_rvalue *ten = gcc_jit_context_new_rvalue_from_int (ctxt, int_type, 10); + gcc_jit_global_set_initializer_rvalue (foo, ten); + gcc_jit_global_set_readonly(foo); +} + +/* { dg-final { jit-verify-output-file-was-created "" } } */ +/* { dg-final { jit-verify-assembler-output ".section\t.rodata" } } */