Declarations#

This section covers the various kinds of declarations that appear in the internal representation, except for declarations of functions (represented by FUNCTION_DECL nodes), which are described in Functions.

Working with declarations#

Some macros can be used with any kind of declaration. These include:

DECL_NAME#

This macro returns an IDENTIFIER_NODE giving the name of the entity.

TREE_TYPE#

This macro returns the type of the entity declared.

EXPR_FILENAME#

This macro returns the name of the file in which the entity was declared, as a char*. For an entity declared implicitly by the compiler (like __builtin_memcpy), this will be the string "<internal>".

EXPR_LINENO#

This macro returns the line number at which the entity was declared, as an int.

DECL_ARTIFICIAL#

This predicate holds if the declaration was implicitly generated by the compiler. For example, this predicate will hold of an implicitly declared member function, or of the TYPE_DECL implicitly generated for a class type. Recall that in C++ code like:

struct S {};

is roughly equivalent to C code like:

struct S {};
typedef struct S S;

The implicitly generated typedef declaration is represented by a TYPE_DECL for which DECL_ARTIFICIAL holds.

The various kinds of declarations include:

LABEL_DECL#

These nodes are used to represent labels in function bodies. For more information, see Functions. These nodes only appear in block scopes.

CONST_DECL#

These nodes are used to represent enumeration constants. The value of the constant is given by DECL_INITIAL which will be an INTEGER_CST with the same type as the TREE_TYPE of the CONST_DECL, i.e., an ENUMERAL_TYPE.

RESULT_DECL#

These nodes represent the value returned by a function. When a value is assigned to a RESULT_DECL, that indicates that the value should be returned, via bitwise copy, by the function. You can use DECL_SIZE and DECL_ALIGN on a RESULT_DECL, just as with a VAR_DECL.

TYPE_DECL#

These nodes represent typedef declarations. The TREE_TYPE is the type declared to have the name given by DECL_NAME. In some cases, there is no associated name.

VAR_DECL#

These nodes represent variables with namespace or block scope, as well as static data members. The DECL_SIZE and DECL_ALIGN are analogous to TYPE_SIZE and TYPE_ALIGN. For a declaration, you should always use the DECL_SIZE and DECL_ALIGN rather than the TYPE_SIZE and TYPE_ALIGN given by the TREE_TYPE, since special attributes may have been applied to the variable to give it a particular size and alignment. You may use the predicates DECL_THIS_STATIC or DECL_THIS_EXTERN to test whether the storage class specifiers static or extern were used to declare a variable.

If this variable is initialized (but does not require a constructor), the DECL_INITIAL will be an expression for the initializer. The initializer should be evaluated, and a bitwise copy into the variable performed. If the DECL_INITIAL is the error_mark_node, there is an initializer, but it is given by an explicit statement later in the code; no bitwise copy is required.

GCC provides an extension that allows either automatic variables, or global variables, to be placed in particular registers. This extension is being used for a particular VAR_DECL if DECL_REGISTER holds for the VAR_DECL, and if DECL_ASSEMBLER_NAME is not equal to DECL_NAME. In that case, DECL_ASSEMBLER_NAME is the name of the register into which the variable will be placed.

PARM_DECL#

Used to represent a parameter to a function. Treat these nodes similarly to VAR_DECL nodes. These nodes only appear in the DECL_ARGUMENTS for a FUNCTION_DECL.

The DECL_ARG_TYPE for a PARM_DECL is the type that will actually be used when a value is passed to this function. It may be a wider type than the TREE_TYPE of the parameter; for example, the ordinary type might be short while the DECL_ARG_TYPE is int.

DEBUG_EXPR_DECL#

Used to represent an anonymous debug-information temporary created to hold an expression as it is optimized away, so that its value can be referenced in debug bind statements.

FIELD_DECL#

These nodes represent non-static data members. The DECL_SIZE and DECL_ALIGN behave as for VAR_DECL nodes. The position of the field within the parent record is specified by a combination of three attributes. DECL_FIELD_OFFSET is the position, counting in bytes, of the DECL_OFFSET_ALIGN -bit sized word containing the bit of the field closest to the beginning of the structure. DECL_FIELD_BIT_OFFSET is the bit offset of the first bit of the field within this word; this may be nonzero even for fields that are not bit-fields, since DECL_OFFSET_ALIGN may be greater than the natural alignment of the field’s type.

If DECL_C_BIT_FIELD holds, this field is a bit-field. In a bit-field, DECL_BIT_FIELD_TYPE also contains the type that was originally specified for it, while DECL_TYPE may be a modified type with lesser precision, according to the size of the bit field.

NAMESPACE_DECL#

Namespaces provide a name hierarchy for other declarations. They appear in the DECL_CONTEXT of other _DECL nodes.

Internal structure#

DECL nodes are represented internally as a hierarchy of structures.

Current structure hierarchy#

struct tree_decl_minimal

This is the minimal structure to inherit from in order for common DECL macros to work. The fields it contains are a unique ID, source location, context, and name.

struct tree_decl_common

This structure inherits from struct tree_decl_minimal. It contains fields that most DECL nodes need, such as a field to store alignment, machine mode, size, and attributes.

struct tree_field_decl

This structure inherits from struct tree_decl_common. It is used to represent FIELD_DECL.

struct tree_label_decl

This structure inherits from struct tree_decl_common. It is used to represent LABEL_DECL.

struct tree_translation_unit_decl

This structure inherits from struct tree_decl_common. It is used to represent TRANSLATION_UNIT_DECL.

struct tree_decl_with_rtl

This structure inherits from struct tree_decl_common. It contains a field to store the low-level RTL associated with a DECL node.

struct tree_result_decl

This structure inherits from struct tree_decl_with_rtl. It is used to represent RESULT_DECL.

struct tree_const_decl

This structure inherits from struct tree_decl_with_rtl. It is used to represent CONST_DECL.

struct tree_parm_decl

This structure inherits from struct tree_decl_with_rtl. It is used to represent PARM_DECL.

struct tree_decl_with_vis

This structure inherits from struct tree_decl_with_rtl. It contains fields necessary to store visibility information, as well as a section name and assembler name.

struct tree_var_decl

This structure inherits from struct tree_decl_with_vis. It is used to represent VAR_DECL.

struct tree_function_decl

This structure inherits from struct tree_decl_with_vis. It is used to represent FUNCTION_DECL.

Adding new DECL node types#

Adding a new DECL tree consists of the following steps

Add a new tree code for the DECL node

For language specific DECL nodes, there is a .def file in each frontend directory where the tree code should be added. For DECL nodes that are part of the middle-end, the code should be added to tree.def.

Create a new structure type for the DECL node

These structures should inherit from one of the existing structures in the language hierarchy by using that structure as the first member.

struct tree_foo_decl
{
   struct tree_decl_with_vis common;
}

Would create a structure name tree_foo_decl that inherits from struct tree_decl_with_vis.

For language specific DECL nodes, this new structure type should go in the appropriate .h file. For DECL nodes that are part of the middle-end, the structure type should go in tree.h.

Add a member to the tree structure enumerator for the node

For garbage collection and dynamic checking purposes, each DECL node structure type is required to have a unique enumerator value specified with it. For language specific DECL nodes, this new enumerator value should go in the appropriate .def file. For DECL nodes that are part of the middle-end, the enumerator values are specified in treestruct.def.

Update union tree_node

In order to make your new structure type usable, it must be added to union tree_node. For language specific DECL nodes, a new entry should be added to the appropriate .h file of the form

struct tree_foo_decl GTY ((tag ("TS_VAR_DECL"))) foo_decl;

For DECL nodes that are part of the middle-end, the additional member goes directly into union tree_node in tree.h.

Update dynamic checking info

In order to be able to check whether accessing a named portion of union tree_node is legal, and whether a certain DECL node contains one of the enumerated DECL node structures in the hierarchy, a simple lookup table is used. This lookup table needs to be kept up to date with the tree structure hierarchy, or else checking and containment macros will fail inappropriately.

For language specific DECL nodes, there is an init_ts function in an appropriate .c file, which initializes the lookup table. Code setting up the table for new DECL nodes should be added there. For each DECL tree code and enumerator value representing a member of the inheritance hierarchy, the table should contain 1 if that tree code inherits (directly or indirectly) from that member. Thus, a FOO_DECL node derived from struct decl_with_rtl, and enumerator value TS_FOO_DECL, would be set up as follows

tree_contains_struct[FOO_DECL][TS_FOO_DECL] = 1;
tree_contains_struct[FOO_DECL][TS_DECL_WRTL] = 1;
tree_contains_struct[FOO_DECL][TS_DECL_COMMON] = 1;
tree_contains_struct[FOO_DECL][TS_DECL_MINIMAL] = 1;

For DECL nodes that are part of the middle-end, the setup code goes into tree.cc.

Add macros to access any new fields and flags

Each added field or flag should have a macro that is used to access it, that performs appropriate checking to ensure only the right type of DECL nodes access the field.

These macros generally take the following form

#define FOO_DECL_FIELDNAME(NODE) FOO_DECL_CHECK(NODE)->foo_decl.fieldname

However, if the structure is simply a base class for further structures, something like the following should be used

#define BASE_STRUCT_CHECK(T) CONTAINS_STRUCT_CHECK(T, TS_BASE_STRUCT)
#define BASE_STRUCT_FIELDNAME(NODE) \
   (BASE_STRUCT_CHECK(NODE)->base_struct.fieldname

Reading them from the generated all-tree.def file (which in turn includes all the tree.def files), gencheck.cc is used during GCC’s build to generate the *_CHECK macros for all tree codes.