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" } } */

Reply via email to