From 03b5288c78b8956fde1df06b197e4328cdce6265 Mon Sep 17 00:00:00 2001 From: Jack Rosenthal Date: Tue, 28 May 2019 22:22:32 -0600 Subject: [PATCH] gccutils: get pretty-printing working again * Add new function ``gcc.is_cplusplus`` to determine if we are compiling C++ * Use ``gcc.is_cplusplus`` in gccutils to not iterate over fullname when we are not using C++ (resolves davidmalcolm#72) * Allow accessing ``gcc.Type.sizeof`` to raise a TypeError while pretty-printing to be silently ignored and not added to attributes * Use ``pp_newline_and_flush`` instead of ``pp_newline`` in ``PyGccPrettyPrinter_as_string`` when we are using GCC 5.3 or later (as this provides the historic functionality relied upon) --- docs/versions.rst | 5 +++++ gcc-python-pretty-printer.c | 8 ++++++++ gcc-python-tree.c | 13 ------------- gcc-python.c | 9 +++++++++ gcc-python.h | 13 +++++++++++++ gccutils/__init__.py | 13 ++++++++++++- 6 files changed, 47 insertions(+), 14 deletions(-) diff --git a/docs/versions.rst b/docs/versions.rst index 0b31e9b6..ec9822ef 100644 --- a/docs/versions.rst +++ b/docs/versions.rst @@ -83,3 +83,8 @@ On my machine, running this currently gives:: 4.8 4008 4.9 4009 =========== ======================== + +.. py:function:: gcc.is_cplusplus() + :rtype: bool + + Determine whether or not we are compiling C++ diff --git a/gcc-python-pretty-printer.c b/gcc-python-pretty-printer.c index be56854b..bef27b4e 100644 --- a/gcc-python-pretty-printer.c +++ b/gcc-python-pretty-printer.c @@ -88,7 +88,15 @@ PyGccPrettyPrinter_as_string(PyObject *obj) ppobj = (struct PyGccPrettyPrinter *)obj; /* Flush the pp first. This forcibly adds a trailing newline: */ +#if (GCC_VERSION < 5003) pp_flush(&ppobj->pp); +#else + /* + * pp_newline_and_flush provides the same functionality on GCC 5.3 + * and later + */ + pp_newline_and_flush(&ppobj->pp); +#endif /* Convert to a python string, leaving off the trailing newline: */ len = strlen(ppobj->buf); diff --git a/gcc-python-tree.c b/gcc-python-tree.c index 369420a1..f4f14f5b 100644 --- a/gcc-python-tree.c +++ b/gcc-python-tree.c @@ -47,19 +47,6 @@ extern PyGccWrapperTypeObject PyGccIntegerCst_TypeObj; __typeof__ (lang_check_failed) lang_check_failed __attribute__ ((weak)); - -/* - Unfortunately, decl_as_string() is only available from the C++ - frontend: cc1plus (it's defined in gcc/cp/error.c). - - See http://gcc.gnu.org/ml/gcc/2011-11/msg00504.html - - Hence we redeclare the symbol as weak, and then check its definition - against 0 before using it. -*/ - -__typeof__ (decl_as_string) decl_as_string __attribute__ ((weak)); - /* Similar for namespace_binding, though gcc 8's r247654 (aka f906dcc33dd818b71e16c88cef38f33c161070db) replaced it with get_namespace_value and reversed the order of the params diff --git a/gcc-python.c b/gcc-python.c index 9e75cd52..61ba9fc8 100644 --- a/gcc-python.c +++ b/gcc-python.c @@ -401,6 +401,12 @@ PyGcc_get_is_lto(PyObject *self, PyObject *noargs) return PyBool_FromLong(in_lto_p); } +static PyObject * +PyGcc_get_is_cplusplus(PyObject *self, PyObject *noargs) +{ + return PyBool_FromLong(decl_as_string != NULL); +} + static PyMethodDef GccMethods[] = { {"register_attribute", (PyCFunction)PyGcc_RegisterAttribute, @@ -491,6 +497,9 @@ static PyMethodDef GccMethods[] = { {"is_lto", PyGcc_get_is_lto, METH_NOARGS, "Determine whether or not we're being invoked during link-time optimization"}, + {"is_cplusplus", PyGcc_get_is_cplusplus, METH_NOARGS, + "Determine whether or not we're compiling C++"}, + /* Garbage collection */ {"_force_garbage_collection", PyGcc__force_garbage_collection, METH_NOARGS, "Forcibly trigger a single run of GCC's garbage collector"}, diff --git a/gcc-python.h b/gcc-python.h index 521cbb79..a1e8b8fb 100644 --- a/gcc-python.h +++ b/gcc-python.h @@ -39,6 +39,7 @@ #include "params.h" #endif #include "gcc-c-api/gcc-cfg.h" +#include "cp/cp-tree.h" /* for decl_as_string */ /* GCC doesn't seem to give us an ID for "invalid event", so invent one: */ #define GCC_PYTHON_PLUGIN_BAD_EVENT (0xffff) @@ -69,6 +70,18 @@ #define CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF(typename) #endif +/* + Unfortunately, decl_as_string() is only available from the C++ + frontend: cc1plus (it's defined in gcc/cp/error.c). + + See http://gcc.gnu.org/ml/gcc/2011-11/msg00504.html + + Hence we redeclare the symbol as weak, and then check its definition + against 0 before using it. +*/ + +__typeof__ (decl_as_string) decl_as_string __attribute__ ((weak)); + /* PyObject shared header for wrapping GCC objects, for integration with GCC's garbage collector (so that things we wrap don't get collected diff --git a/gccutils/__init__.py b/gccutils/__init__.py index fada3662..2bfbbdfc 100644 --- a/gccutils/__init__.py +++ b/gccutils/__init__.py @@ -148,7 +148,18 @@ def iter_tree_attrs(self, obj): # Ignore private and "magic" attributes: if name.startswith('_'): continue - value = getattr(obj, name) + if (isinstance(obj, gcc.FunctionDecl) + and name == 'fullname' + and not gcc.is_cplusplus()): + continue + try: + value = getattr(obj, name) + except TypeError as e: + # for gcc.Type, sizeof is not always defined, and + # TypeError is raise under this condition + if not isinstance(obj, gcc.Type) or name != 'sizeof': + raise e + continue # Ignore methods: if hasattr(value, '__call__'): continue