https://gcc.gnu.org/g:2486234b5ae0d71ca7bbdc6e216b4707cd5bef15
commit r15-2284-g2486234b5ae0d71ca7bbdc6e216b4707cd5bef15 Author: David Malcolm <dmalc...@redhat.com> Date: Wed Jul 24 18:07:53 2024 -0400 json: support std::unique_ptr in array::append and object::set This patch uses templates to add overloads of json::array::append and json::object::set taking std::unique_ptr<T> where T is a subclass of json::value. Doing so makes it much easier to track memory ownership and enforce schema validity when constructing non-trivial JSON; using the wrong kind of JSON value leads to compile-time errors like the following: error: cannot convert ‘unique_ptr<sarif_message>’ to ‘unique_ptr<sarif_log>’ 629 | location_obj->set<sarif_log> ("message", std::move (message_obj)); | ~~~~~~~~~~^~~~~~~~~~~~~ | | | unique_ptr<sarif_message> No functional change intended. gcc/ChangeLog: * diagnostic-format-json.cc: Define INCLUDE_MEMORY. * diagnostic-format-sarif.cc: Likewise. * dumpfile.cc: Likewise. * gcov.cc: Likewise. * json.cc: Likewise. Include "make-unique.h". (selftest::test_formatting): Exercise overloads of array::append and object::set that use unique_ptr. * json.h: Require INCLUDE_MEMORY to have been defined. (json::object::set): Add a template to add a family of overloads taking a std::unique_ptr<JsonType> (json::array::append): Likewise. * optinfo-emit-json.cc: Define INCLUDE_MEMORY. * optinfo.cc: Likewise. * timevar.cc: Likewise. * toplev.cc: Likewise. * tree-diagnostic-client-data-hooks.cc: Likewise. Signed-off-by: David Malcolm <dmalc...@redhat.com> Diff: --- gcc/diagnostic-format-json.cc | 1 + gcc/diagnostic-format-sarif.cc | 1 + gcc/dumpfile.cc | 1 + gcc/gcov.cc | 1 + gcc/json.cc | 17 +++++++++----- gcc/json.h | 38 ++++++++++++++++++++++++++++++++ gcc/optinfo-emit-json.cc | 1 + gcc/optinfo.cc | 1 + gcc/timevar.cc | 1 + gcc/toplev.cc | 1 + gcc/tree-diagnostic-client-data-hooks.cc | 1 + 11 files changed, 58 insertions(+), 6 deletions(-) diff --git a/gcc/diagnostic-format-json.cc b/gcc/diagnostic-format-json.cc index 1bf8da663cc2..55ba39e0c532 100644 --- a/gcc/diagnostic-format-json.cc +++ b/gcc/diagnostic-format-json.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "diagnostic.h" diff --git a/gcc/diagnostic-format-sarif.cc b/gcc/diagnostic-format-sarif.cc index d6de5806f5ac..6aba81c6ac9b 100644 --- a/gcc/diagnostic-format-sarif.cc +++ b/gcc/diagnostic-format-sarif.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see #include "config.h" +#define INCLUDE_MEMORY #define INCLUDE_VECTOR #include "system.h" #include "coretypes.h" diff --git a/gcc/dumpfile.cc b/gcc/dumpfile.cc index 82bd8b06bebf..6353c0857449 100644 --- a/gcc/dumpfile.cc +++ b/gcc/dumpfile.cc @@ -18,6 +18,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "options.h" diff --git a/gcc/gcov.cc b/gcc/gcov.cc index 85fdac4368e8..aa016c658ce0 100644 --- a/gcc/gcov.cc +++ b/gcc/gcov.cc @@ -32,6 +32,7 @@ along with Gcov; see the file COPYING3. If not see #include "config.h" #define INCLUDE_ALGORITHM +#define INCLUDE_MEMORY #define INCLUDE_VECTOR #define INCLUDE_STRING #define INCLUDE_MAP diff --git a/gcc/json.cc b/gcc/json.cc index 86490259dabf..275ef486faf1 100644 --- a/gcc/json.cc +++ b/gcc/json.cc @@ -19,11 +19,13 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "json.h" #include "pretty-print.h" #include "math.h" +#include "make-unique.h" #include "selftest.h" using namespace json; @@ -499,28 +501,31 @@ test_writing_literals () ASSERT_PRINT_EQ (literal (false), true, "false"); } -/* Verify that nested values are formatted correctly when written. */ +/* Verify that nested values are formatted correctly when written. + + Also, make use of array::append(std::unique_ptr<value>) and + object::set (const char *key, std::unique_ptr<value> v).*/ static void test_formatting () { object obj; object *child = new object; - object *grandchild = new object; + std::unique_ptr<object> grandchild = ::make_unique<object> (); obj.set_string ("str", "bar"); obj.set ("child", child); obj.set_integer ("int", 42); - child->set ("grandchild", grandchild); - child->set_integer ("int", 1776); - array *arr = new array; for (int i = 0; i < 3; i++) - arr->append (new integer_number (i)); + arr->append (::make_unique<integer_number> (i)); grandchild->set ("arr", arr); grandchild->set_integer ("int", 1066); + child->set ("grandchild", std::move (grandchild)); + child->set_integer ("int", 1776); + /* This test relies on json::object writing out key/value pairs in key-insertion order. */ ASSERT_PRINT_EQ (obj, true, diff --git a/gcc/json.h b/gcc/json.h index d3493a72d525..f80a5e82caf3 100644 --- a/gcc/json.h +++ b/gcc/json.h @@ -21,6 +21,15 @@ along with GCC; see the file COPYING3. If not see #ifndef GCC_JSON_H #define GCC_JSON_H +/* This header uses std::unique_ptr, but <memory> can't be directly + included due to issues with macros. Hence <memory> must be included + from system.h by defining INCLUDE_MEMORY in any source file using + json.h. */ + +#ifndef INCLUDE_MEMORY +# error "You must define INCLUDE_MEMORY before including system.h to use make-unique.h" +#endif + /* Implementation of JSON, a lightweight data-interchange format. See http://www.json.org/ @@ -101,6 +110,21 @@ class object : public value void print (pretty_printer *pp, bool formatted) const final override; void set (const char *key, value *v); + + /* Set the property KEY of this object, requiring V + to be of a specific json::value subclass. + + This can be used to enforce type-checking, making it easier + to comply with a schema, e.g. + obj->set<some_subclass> ("property_name", value) + leading to a compile-time error if VALUE is not of the + appropriate subclass. */ + template <typename JsonType> + void set (const char *key, std::unique_ptr<JsonType> v) + { + set (key, v.release ()); + } + value *get (const char *key) const; void set_string (const char *key, const char *utf8_value); @@ -132,6 +156,20 @@ class array : public value void append (value *v); void append_string (const char *utf8_value); + /* Append V to this array, requiring V + to be a specific json::value subclass. + + This can be used to enforce type-checking, making it easier + to comply with a schema, e.g. + arr->append<some_subclass> (value) + leading to a compile-time error if VALUE is not of the + appropriate subclass. */ + template <typename JsonType> + void append (std::unique_ptr<JsonType> v) + { + append (v.release ()); + } + private: auto_vec<value *> m_elements; }; diff --git a/gcc/optinfo-emit-json.cc b/gcc/optinfo-emit-json.cc index faae95fc232a..87a05a72dd3c 100644 --- a/gcc/optinfo-emit-json.cc +++ b/gcc/optinfo-emit-json.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" diff --git a/gcc/optinfo.cc b/gcc/optinfo.cc index 3048581cf074..7a8256171744 100644 --- a/gcc/optinfo.cc +++ b/gcc/optinfo.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" diff --git a/gcc/timevar.cc b/gcc/timevar.cc index 36d95336949d..68bcf44864f9 100644 --- a/gcc/timevar.cc +++ b/gcc/timevar.cc @@ -19,6 +19,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "timevar.h" diff --git a/gcc/toplev.cc b/gcc/toplev.cc index 8933a89bd281..d9e8b34ae7ca 100644 --- a/gcc/toplev.cc +++ b/gcc/toplev.cc @@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see Error messages and low-level interface to malloc also handled here. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "backend.h" diff --git a/gcc/tree-diagnostic-client-data-hooks.cc b/gcc/tree-diagnostic-client-data-hooks.cc index 3e8b031e2cc5..a2e4a5c97bd5 100644 --- a/gcc/tree-diagnostic-client-data-hooks.cc +++ b/gcc/tree-diagnostic-client-data-hooks.cc @@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see <http://www.gnu.org/licenses/>. */ #include "config.h" +#define INCLUDE_MEMORY #include "system.h" #include "coretypes.h" #include "version.h"