Fixing declarations

Sometimes the process of transforming code involves modifying declarations. A declaration in C/C++ is just a syntactic construct that introduces a name. We will not dwelve into the details of declaration syntax itself, today, but learn how to modify them.

Remember that modifying the tree is always a delicate operation (it is rather easy to render it invalid with bogus information), so we must try to minimize the harm done in the tree itself. The easiest way to modify declarations, thus, is removing what it is unneeded and adding the new declarations.

Imagine, hypothetically, you want to replace references to an array because, after some kind of analysis, you figure out it is safe to do and prefer to use scalars instead (Needless to say that any aggressive compiler will be much smarter than that).

So, instead of

int a[2];
a[0] = 3;
a[1] = 4;
f(a[0], a[1]);

we will want

int a_0, a_1;
a_0 = 3;
a_1 = 4;
f(a_0, a_1);

To get the declaration point of a Symbol we can use Symbol::get_point_of_declaration. This returns an AST_t which may or may not be valid: this is because symbols can be declared in so many ways and maybe even not in the code itself! If the tree is valid, you can wrap it in a Declaration.

Declaration class offers a nicer interface to the declaration itself. You will want it just for the purpose of the declaration itself. Any other information: like type or properties of the symbol are already in Type and Symbol respectively (remember that you can get the Type of a Symbol using Symbol::get_type). A Declaration in C and C++ can declare more than one thing, like in

int a, b[10], c(float);

which declares, in this order, an int variable, an array 10 of int variable and a function (float) returning int called c.  To get the list of declared entities one can use Declaration::get_declared_entities which returns a list of DeclaredEntity. You can get the Symbol of the particular declaration. If you have to remove a declaration, and the declaration itself only declares one entity: you should remove the whole Declaration, otherwise just remove the particular DeclaredEntity. To remove the tree, you will have to use AST_t::remove_in_list on the AST_t obtained from Declaration or DeclaredEntity, accordingly.

If you simply remove the DeclaredEntity of a Declaration with only one declared entity, you will end with a tree like this

int ;

which is invalid.

Note that Declaration and DeclaredEntity should be used only when you are concerned on the tree. Almost all the information there is already in Symbol and Type.

Once you have removed the declaration, sometimes it may happen that you need to redeclare the same symbol again but in a different shape. As an example, this happens for the OpenMP #pragma omp threadprivate directive.

int bar;
#pragma omp threadprivate(bar)

Must be translated into

__thread int bar;

which involves redeclaring bar, again, just to get a sane tree, but the frontend would not allow such a thing. To allow a redeclaration we can use Source::ALLOW_REDECLARATION as the third parameter of Source::parse_declaration (or other parse_* functions).