commit 2bb77306c37bb03a616c2554cfbf25dc02640b43
Author: David Malcolm <dmalcolm(a)redhat.com>
Date: Wed Nov 30 16:34:37 2011 -0500
C++ support
Add "fullname" attribute to gcc.FunctionDecl, but only when the plugin is
invoked from the C++ frontend (cc1plus), gracefully handling the case when
we're invoked from other language frontends.
Add "is_public", "is_private", "is_protected",
"is_static" boolean attributes
to gcc.FunctionDecl
Add "argument_types" attribute to gcc.MethodType
docs/tree.rst | 56 +++
gcc-python-tree.c | 42 ++
gcc-python-wrappers.h | 6 +
generate-tree-c.py | 25 ++-
tests/examples/cplusplus/classes/input.cc | 89 +++++
tests/examples/cplusplus/classes/script.py | 63 ++++
tests/examples/cplusplus/classes/stdout.txt | 391 ++++++++++++++++++++
.../language-specific-errors/fullname/input.c | 31 ++
.../language-specific-errors/fullname/script.py | 32 ++
.../language-specific-errors/fullname/stderr.txt | 6 +
.../language-specific-errors/fullname/stdout.txt | 2 +
11 files changed, 741 insertions(+), 2 deletions(-)
---
diff --git a/docs/tree.rst b/docs/tree.rst
index b766853..919c3e9 100644
--- a/docs/tree.rst
+++ b/docs/tree.rst
@@ -216,11 +216,55 @@ Declarations
The :py:class:`gcc.ResultDecl` representing the return value of this
function
+ .. py:attribute:: fullname
+
+ .. note:: This attribute is only usable with C++ code. Attempting to use
+ it from another language will lead to a `RuntimeError` exception.
+
+ (string) The "full name" of this function, including the scope, return
+ type and default arguments.
+
+ For example, given this code:
+
+ .. code-block:: c++
+
+ namespace Example {
+ struct Coord {
+ int x;
+ int y;
+ };
+
+ class Widget {
+ public:
+ void set_location(const struct Coord& coord);
+ };
+ };
+
+ `set_location`'s fullname is::
+
+ 'void Example::Widget::set_location(const Example::Coord&)'
+
.. py:attribute:: callgraph_node
The :py:class:`gcc.CallgraphNode` for this function declaration, or
`None`
+ .. py:attribute:: is_public
+
+ (bool) For C++: is this declaration "public"
+
+ .. py:attribute:: is_private
+
+ (bool) For C++: is this declaration "private"
+
+ .. py:attribute:: is_protected
+
+ (bool) For C++: is this declaration "protected"
+
+ .. py:attribute:: is_static
+
+ (bool) For C++: is this declaration "static"
+
.. py:class:: gcc.VarDecl
A subclass of :py:class:`gcc.Declaration` indicating the declaration of a
@@ -416,6 +460,18 @@ Additional attributes for various :py:class:`gcc.Type` subclasses:
* the attribute is present, with a list of 1-based argument indices
(Note that the result is still 0-based)
+.. py:class:: gcc.MethodType
+
+ Subclass of :py:class:`gcc.Type` representing the type of a given method.
+ Similar to :py:class:`gcc.FunctionType`
+
+ The `type` attribute holds the return type.
+
+ .. py:attribute:: argument_types
+
+ A tuple of :py:class:`gcc.Type` instances, representing the function's
+ argument types
+
Constants
---------
diff --git a/gcc-python-tree.c b/gcc-python-tree.c
index 625938e..3ba3b4c 100644
--- a/gcc-python-tree.c
+++ b/gcc-python-tree.c
@@ -23,6 +23,8 @@
#include "gcc-python-compat.h"
#include "gimple.h"
+#include "cp/cp-tree.h" /* for TFF_* for use by gcc_FunctionDecl_get_fullname
*/
+
//#include "rtl.h"
/*
"struct rtx_def" is declarted within rtl.h, c.f:
@@ -154,6 +156,41 @@ error:
}
PyObject *
+gcc_FunctionDecl_get_fullname(struct PyGccTree *self, void *closure)
+{
+ /*
+ 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 try to dynamically load the symbol, which will be already
+ present if we were loaded by cc1plus (for C++), and not be found
+ otherwise
+
+ Declared in cp/cp-tree.h as:
+ extern const char *decl_as_string (tree, int);
+ */
+
+ const char *(*decl_as_string)(tree, int);
+ const char *str;
+
+ decl_as_string = dlsym(RTLD_DEFAULT, "decl_as_string");
+
+ if (NULL == decl_as_string) {
+ return PyErr_Format(PyExc_RuntimeError,
+ "attribute 'fullname' is only available when
compiling C++ code");
+ }
+
+ str = decl_as_string(self->t,
+ TFF_DECL_SPECIFIERS
+ |TFF_RETURN_TYPE
+ |TFF_FUNCTION_DEFAULT_ARGUMENTS
+ |TFF_EXCEPTION_SPECIFICATION);
+ return gcc_python_string_from_string(str);
+}
+
+PyObject *
gcc_IdentifierNode_repr(struct PyGccTree * self)
{
if (IDENTIFIER_POINTER(self->t)) {
@@ -297,6 +334,11 @@ gcc_FunctionType_get_argument_types(struct PyGccTree * self, void
*closure)
return NULL;
}
+PyObject *
+gcc_MethodType_get_argument_types(struct PyGccTree * self,void *closure)
+{
+ return gcc_FunctionType_get_argument_types(self, closure);
+}
PyObject *
gcc_Constructor_get_elements(PyObject *self, void *closure)
diff --git a/gcc-python-wrappers.h b/gcc-python-wrappers.h
index fc3bf8e..b1f3986 100644
--- a/gcc-python-wrappers.h
+++ b/gcc-python-wrappers.h
@@ -109,6 +109,9 @@ PyObject *
gcc_Declaration_repr(struct PyGccTree * self);
PyObject *
+gcc_FunctionDecl_get_fullname(struct PyGccTree *self, void *closure);
+
+PyObject *
gcc_IdentifierNode_repr(struct PyGccTree * self);
PyObject *
@@ -130,6 +133,9 @@ PyObject *
gcc_IntegerConstant_repr(struct PyGccTree * self);
PyObject *
+gcc_MethodType_get_argument_types(struct PyGccTree * self,void *closure);
+
+PyObject *
gcc_StringConstant_repr(struct PyGccTree * self);
PyObject *
diff --git a/generate-tree-c.py b/generate-tree-c.py
index 079bb1b..923b801 100644
--- a/generate-tree-c.py
+++ b/generate-tree-c.py
@@ -63,7 +63,10 @@ gcc_Tree_get_addr(struct PyGccTree *self, void *closure)
PyGetSetDef('addr',
'gcc_Tree_get_addr', None,
'The address of the underlying GCC
object in memory'),
PyGetSetDef('str_no_uid',
'gcc_Tree_get_str_no_uid', None,
- 'A string representation of this
object, like str(), but without including any internal UID')])
+ 'A string representation of this
object, like str(), but without including any internal UID')],
+ identifier_prefix='gcc_Tree',
+ typename='PyGccTree')
+
cu.add_defn(getsettable.c_defn())
pytype = PyTypeObject(identifier = 'gcc_TreeType',
@@ -298,7 +301,9 @@ def generate_tree_code_classes():
cc = tree_type.camel_cased_string()
- getsettable = PyGetSetDefTable('gcc_%s_getset_table' % cc, [])
+ getsettable = PyGetSetDefTable('gcc_%s_getset_table' % cc, [],
+ identifier_prefix='gcc_%s' % cc,
+ typename='PyGccTree')
tp_as_number = None
tp_repr = None
@@ -462,7 +467,17 @@ def generate_tree_code_classes():
None,
"A tuple of gcc.Type instances, representing the
argument types of this function type")
+ if tree_type.SYM == 'METHOD_TYPE':
+ getsettable.add_gsdef('argument_types',
+ 'gcc_MethodType_get_argument_types',
+ None,
+ "A tuple of gcc.Type instances, representing the
argument types of this method type")
+
if tree_type.SYM == 'FUNCTION_DECL':
+ getsettable.add_gsdef('fullname',
+ 'gcc_FunctionDecl_get_fullname',
+ None,
+ 'C++ only: the full name of this function
declaration')
add_simple_getter('function',
'gcc_python_make_wrapper_function(DECL_STRUCT_FUNCTION(self->t))',
'The gcc.Function (or None) for this declaration')
@@ -476,6 +491,12 @@ def generate_tree_code_classes():
'gcc_python_make_wrapper_cgraph_node(cgraph_get_node(self->t))',
'The gcc.CallgraphNode for this function declaration,
or None')
+ for attr in ('public', 'private', 'protected',
'static'):
+ getsettable.add_simple_getter(cu,
+ 'is_%s' % attr,
+
'PyBool_FromLong(TREE_%s(self->t))' % attr.upper(),
+ None)
+
if tree_type.SYM == 'SSA_NAME':
# c.f. "struct GTY(()) tree_ssa_name":
add_simple_getter('var',
diff --git a/tests/examples/cplusplus/classes/input.cc
b/tests/examples/cplusplus/classes/input.cc
new file mode 100644
index 0000000..10032a0
--- /dev/null
+++ b/tests/examples/cplusplus/classes/input.cc
@@ -0,0 +1,89 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2011 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <
http://www.gnu.org/licenses/>.
+*/
+
+/* Examples of various aspects of C++ syntax */
+namespace Example {
+ struct Coord {
+ int x;
+ int y;
+ };
+
+ class Widget {
+ protected:
+ Widget() {
+ }
+ public:
+ virtual ~Widget() {
+ }
+
+ /* Example of a pure virtual method */
+ virtual int get_width() = 0;
+
+ /* Reference: */
+ void set_location(const struct Coord& coord);
+
+ private:
+ struct Coord m_location;
+ };
+
+ class Dialog : public Widget {
+ public:
+ Dialog(): Widget() {
+ }
+
+ ~Dialog() {}
+
+ int get_width() { return 400; }
+ };
+};
+
+/* Example of a method definition, outside of the body of the class */
+void Example::Widget::set_location(const struct Coord& coord)
+{
+ this->m_location = coord;
+}
+
+/* Examples of overloaded functions: */
+void foo()
+{
+}
+
+void foo(const char *str)
+{
+}
+
+void foo(const Example::Coord& coord)
+{
+ /* Example of a call to a non-virtual method: */
+ Example::Widget *dlg = new Example::Dialog();
+ dlg->set_location(coord);
+ delete dlg;
+
+}
+
+
+
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/examples/cplusplus/classes/script.py
b/tests/examples/cplusplus/classes/script.py
new file mode 100644
index 0000000..2071b95
--- /dev/null
+++ b/tests/examples/cplusplus/classes/script.py
@@ -0,0 +1,63 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <
http://www.gnu.org/licenses/>.
+
+import gcc
+
+class TestPass(gcc.GimplePass):
+ def execute(self, fn):
+ print('fn: %r' % fn)
+ print(' fn.decl.name: %r' % fn.decl.name)
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+ print(' str(fn.decl): %s' % fn.decl)
+ print(' type(fn): %r' % type(fn))
+ print(' type(fn.decl): %r' % type(fn.decl))
+ print(' type(fn.decl.type): %r' % type(fn.decl.type))
+
+ for attr in ('public', 'private', 'protected',
'static'):
+ print(' fn.decl.is_%s: %r' % (attr, getattr(fn.decl, 'is_%s'
% attr)))
+
+ #fn.decl.debug()
+
+ # fn.decl is an instance of gcc.FunctionDecl:
+ print(' return type: %r' % str(fn.decl.type.type))
+ # fn.decl.type is an instance of gcc.MethodType for the methods:
+ print(' argument types: %r' % [str(t) for t in
fn.decl.type.argument_types])
+
+ assert isinstance(fn.cfg, gcc.Cfg) # None for some early passes
+ assert fn.cfg.basic_blocks[0] == fn.cfg.entry
+ assert fn.cfg.basic_blocks[1] == fn.cfg.exit
+ for blockidx, bb in enumerate(fn.cfg.basic_blocks):
+ if bb.gimple:
+ print(' block %i' % blockidx)
+ for i,stmt in enumerate(bb.gimple):
+ print(' gimple[%i]:' % i)
+ print(' str(stmt): %r' % str(stmt))
+ print(' repr(stmt): %r' % repr(stmt))
+ if isinstance(stmt, gcc.GimpleCall):
+ print(' type(stmt.fn): %r' % type(stmt.fn))
+ print(' str(stmt.fn): %r' % str(stmt.fn))
+ print(' stmt.fn: %r' % stmt.fn)
+ if isinstance(stmt.fn, gcc.AddrExpr):
+ print(' stmt.fn.operand: %r' % stmt.fn.operand)
+ print(' stmt.fn.operand.fullname: %r' %
stmt.fn.operand.fullname)
+ for i, arg in enumerate(stmt.args):
+ print(' str(stmt.args[%i]): %r' % (i,
str(stmt.args[i])))
+ print(' str(stmt.lhs): %s' % str(stmt.lhs))
+
+test_pass = TestPass(name='test-pass')
+test_pass.register_after('cfg')
diff --git a/tests/examples/cplusplus/classes/stdout.txt
b/tests/examples/cplusplus/classes/stdout.txt
new file mode 100644
index 0000000..f1cbdde
--- /dev/null
+++ b/tests/examples/cplusplus/classes/stdout.txt
@@ -0,0 +1,391 @@
+fn: gcc.Function('__base_dtor ')
+ fn.decl.name: '__base_dtor '
+ fn.decl.fullname: 'Example::Widget::~Widget()'
+ str(fn.decl): gcc.FunctionDecl('__base_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->_vptr.Widget = &_ZTVN7Example6WidgetE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = 0 & 1;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = (bool) D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'if (D.nnnnn != 0)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 4
+ gimple[0]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 5
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_dtor ')
+ fn.decl.name: '__base_dtor '
+ fn.decl.fullname: 'Example::Dialog::~Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__base_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->D.nnnnn._vptr.Widget =
&_ZTVN7Example6DialogE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'Example::Widget::~Widget (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__base_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__base_dtor ')
+ stmt.fn.operand.fullname: 'Example::Widget::~Widget()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = 0 & 1;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = (bool) D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'if (D.nnnnn != 0)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 4
+ gimple[0]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 5
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo(const Example::Coord&)'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['const struct Coord &']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = operator new (16);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator new'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator new')
+ stmt.fn.operand.fullname: 'void* operator new(long unsigned int) throw
(std::bad_alloc)'
+ str(stmt.args[0]): '16'
+ str(stmt.lhs): gcc.VarDecl(nnnn)
+ gimple[1]:
+ str(stmt): 'dlg.0 = D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'Example::Dialog::Dialog (dlg.0);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_ctor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_ctor ')
+ stmt.fn.operand.fullname: 'Example::Dialog::Dialog()'
+ str(stmt.args[0]): "gcc.VarDecl('dlg.0')"
+ str(stmt.lhs): None
+ gimple[3]:
+ str(stmt): 'dlg = dlg.0;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[4]:
+ str(stmt): 'Example::Widget::set_location (dlg, coord);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'set_location'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('set_location')
+ stmt.fn.operand.fullname: 'void Example::Widget::set_location(const
Example::Coord&)'
+ str(stmt.args[0]): "gcc.VarDecl('dlg')"
+ str(stmt.args[1]): "gcc.ParmDecl('coord')"
+ str(stmt.lhs): None
+ gimple[5]:
+ str(stmt): 'if (dlg != 0B)'
+ repr(stmt): 'gcc.GimpleCond()'
+ block 3
+ gimple[0]:
+ str(stmt): 'D.nnnnn = dlg->_vptr.Widget;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'D.nnnnn = D.nnnnn + 8;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[2]:
+ str(stmt): 'D.nnnnn = *D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'OBJ_TYPE_REF(D.nnnnn;dlg->1) (dlg);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.ObjTypeRef'>
+ str(stmt.fn): 'OBJ_TYPE_REF(D.nnnnn;dlg->1)'
+ stmt.fn: <gcc.ObjTypeRef object at 0xdeadbeef>
+ str(stmt.args[0]): "gcc.VarDecl('dlg')"
+ str(stmt.lhs): None
+ block 4
+ gimple[0]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_ctor ')
+ fn.decl.name: '__base_ctor '
+ fn.decl.fullname: 'Example::Dialog::Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__base_ctor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = &this->D.nnnnn;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'Example::Widget::Widget (D.nnnnn);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__base_ctor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__base_ctor ')
+ stmt.fn.operand.fullname: 'Example::Widget::Widget()'
+ str(stmt.args[0]): 'gcc.VarDecl(nnnn)'
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'this->D.nnnnn._vptr.Widget =
&_ZTVN7Example6DialogE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[3]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__base_ctor ')
+ fn.decl.name: '__base_ctor '
+ fn.decl.fullname: 'Example::Widget::Widget()'
+ str(fn.decl): gcc.FunctionDecl('__base_ctor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: True
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->_vptr.Widget = &_ZTVN7Example6WidgetE[2];'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo(const char*)'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['const char *']
+ block 2
+ gimple[0]:
+ str(stmt): 'GIMPLE_NOP'
+ repr(stmt): 'gcc.GimpleNop()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'
+ fn.decl.fullname: 'void foo()'
+ str(fn.decl): gcc.FunctionDecl('foo')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.FunctionType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: []
+ block 2
+ gimple[0]:
+ str(stmt): 'GIMPLE_NOP'
+ repr(stmt): 'gcc.GimpleNop()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('set_location')
+ fn.decl.name: 'set_location'
+ fn.decl.fullname: 'void Example::Widget::set_location(const
Example::Coord&)'
+ str(fn.decl): gcc.FunctionDecl('set_location')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *', 'const struct Coord &']
+ block 2
+ gimple[0]:
+ str(stmt): 'this->m_location = *coord;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('get_width')
+ fn.decl.name: 'get_width'
+ fn.decl.fullname: 'virtual int Example::Dialog::get_width()'
+ str(fn.decl): gcc.FunctionDecl('get_width')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'int'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'D.nnnnn = 400;'
+ repr(stmt): 'gcc.GimpleAssign()'
+ gimple[1]:
+ str(stmt): 'return D.nnnnn;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__deleting_dtor ')
+ fn.decl.name: '__deleting_dtor '
+ fn.decl.fullname: 'virtual Example::Dialog::~Dialog()'
+ str(fn.decl): gcc.FunctionDecl('__deleting_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Dialog *']
+ block 2
+ gimple[0]:
+ str(stmt): 'Example::Dialog::~Dialog (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_dtor ')
+ stmt.fn.operand.fullname: 'virtual Example::Dialog::~Dialog()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
+fn: gcc.Function('__deleting_dtor ')
+ fn.decl.name: '__deleting_dtor '
+ fn.decl.fullname: 'virtual Example::Widget::~Widget()'
+ str(fn.decl): gcc.FunctionDecl('__deleting_dtor ')
+ type(fn): <type 'gcc.Function'>
+ type(fn.decl): <type 'gcc.FunctionDecl'>
+ type(fn.decl.type): <type 'gcc.MethodType'>
+ fn.decl.is_public: True
+ fn.decl.is_private: False
+ fn.decl.is_protected: False
+ fn.decl.is_static: True
+ return type: 'void'
+ argument types: ['struct Widget *']
+ block 2
+ gimple[0]:
+ str(stmt): 'Example::Widget::~Widget (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): '__comp_dtor '
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('__comp_dtor ')
+ stmt.fn.operand.fullname: 'virtual Example::Widget::~Widget()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ block 3
+ gimple[0]:
+ str(stmt): '<L0>:'
+ repr(stmt): 'gcc.GimpleLabel()'
+ gimple[1]:
+ str(stmt): 'operator delete (this);'
+ repr(stmt): 'gcc.GimpleCall()'
+ type(stmt.fn): <type 'gcc.AddrExpr'>
+ str(stmt.fn): 'operator delete'
+ stmt.fn: <gcc.AddrExpr object at 0xdeadbeef>
+ stmt.fn.operand: gcc.FunctionDecl('operator delete')
+ stmt.fn.operand.fullname: 'void operator delete(void*) throw ()'
+ str(stmt.args[0]): "gcc.ParmDecl('this')"
+ str(stmt.lhs): None
+ gimple[2]:
+ str(stmt): 'return;'
+ repr(stmt): 'gcc.GimpleReturn()'
diff --git a/tests/plugin/language-specific-errors/fullname/input.c
b/tests/plugin/language-specific-errors/fullname/input.c
new file mode 100644
index 0000000..5fc1a4d
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/input.c
@@ -0,0 +1,31 @@
+/*
+ Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+ Copyright 2011 Red Hat, Inc.
+
+ This is free software: you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see
+ <
http://www.gnu.org/licenses/>.
+*/
+
+void foo(int x, int y)
+{
+}
+
+
+/*
+ PEP-7
+Local variables:
+c-basic-offset: 4
+indent-tabs-mode: nil
+End:
+*/
diff --git a/tests/plugin/language-specific-errors/fullname/script.py
b/tests/plugin/language-specific-errors/fullname/script.py
new file mode 100644
index 0000000..9a65f84
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/script.py
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+# Copyright 2011 David Malcolm <dmalcolm(a)redhat.com>
+# Copyright 2011 Red Hat, Inc.
+#
+# This is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see
+# <
http://www.gnu.org/licenses/>.
+
+# Verify that an attempt to use the "fullname" attribute outside of C++
+# is gracefully handled
+
+import gcc
+
+class TestPass(gcc.GimplePass):
+ def execute(self, fn):
+ print('fn: %r' % fn)
+ print(' fn.decl.name: %r' % fn.decl.name)
+ # This ought to raise a RuntimeError
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+
+test_pass = TestPass(name='test-pass')
+test_pass.register_after('cfg')
diff --git a/tests/plugin/language-specific-errors/fullname/stderr.txt
b/tests/plugin/language-specific-errors/fullname/stderr.txt
new file mode 100644
index 0000000..455762f
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/stderr.txt
@@ -0,0 +1,6 @@
+tests/plugin/language-specific-errors/fullname/input.c: In function 'foo':
+tests/plugin/language-specific-errors/fullname/input.c:21:1: error: Unhandled Python
exception raised calling 'execute' method
+Traceback (most recent call last):
+ File "tests/plugin/language-specific-errors/fullname/script.py", line 29, in
execute
+ print(' fn.decl.fullname: %r' % fn.decl.fullname)
+RuntimeError: attribute 'fullname' is only available when compiling C++ code
diff --git a/tests/plugin/language-specific-errors/fullname/stdout.txt
b/tests/plugin/language-specific-errors/fullname/stdout.txt
new file mode 100644
index 0000000..f315c93
--- /dev/null
+++ b/tests/plugin/language-specific-errors/fullname/stdout.txt
@@ -0,0 +1,2 @@
+fn: gcc.Function('foo')
+ fn.decl.name: 'foo'