CPP Template Specialization

Olivier J. G. olivier.jg at gmail.com
Tue Apr 24 05:18:07 UTC 2012


I've been digging around the CPP template support off and on for a
couple weeks, mainly writing tests and hacking past issues they run
into.
I've managed to get it to pass some complexish tests (focusing on
function specialization, for now), but there are some issues I want to
get some feedback on (esp from David, of course, but I provide
background on my questions to make them accessible).

1. FunctionDeclaration as a ForwardDeclaration
Currently CPP support apparently considers a FunctionDeclaration to
have a one-to-one mapping to a FunctionDefinition. This is not the
case. A function declaration is a forward declaration of sorts, and
you can have many or none of them for non-class-member functions. This
isn't very noticeable for most C++ projects probably (but C
projects...). Where it gets in my way is
class-member-function-specilalization-declarations-that-aren't-definitions
(mouthful) that might exist. Only the actual definition should (and
can) be specializedFrom(), as that's all that can correctly be unique.
On the other hand, when it finds a specialization declaration, it
should not attempt an instantiation (even though there may not be any
specializedFrom definition yet in scope). At this point I have no fix
for this, I simply ignore such declaration-only specializations.


2. Specialization vs Instantiation inconsistancy
Specializations are tracked by TemplateDeclarations alongside the
instantiations in m_instantiations. As far as terminology goes, this
is undesirable, but it's a generally useful abstraction that could
possibly use a rename. Anyhow, apparently this wasn't always the case.
It /seems/ that in the past specializations were instantiatedFrom
nullptr (but with correct templ params). Currently on "instantiation"
(actually instantiation /or/ "recognition") of a specialization, the
specialization is setInstantiatedFrom its origin, so when a particular
instantiation is looked for later, it can provide the specialization.
The problem is that whenever it deletes its instantiations (ie,
anytime another declaration is specializedFrom it, or on a reparse) it
simply unregisters all non-anonymously inserted declarations (which
should include all specializations). This causes problems where a
later specialization will be specializedFrom the wrong decl. I've
fixed this by deleting all non-anonymously inserted functions in
deleteAllInstantiations, except when the origin function is about to
be deleted, so it doesn't crash when deleting a specialization after
its origin (funky hacking to get things working). I'd like to know
three things:
a. Why is it that some instantiations (that is, not specializations)
are inserted into contexts non-anonymously?
b. Why is it that deleteAllInstantiations would not delete these
non-specialization instantiations?
c. I've assumed that the plan is for m_instantiations to be a mapping
from template parameters to Declaration, whether it's an instantiation
or actually a specialization. Is there actually some other way this is
intended to be handled?


3. Function specialization context imports
Currently there are two kinds of DUContext::Import. One kind stores a
DeclarationId, which is resolved, and the context given via the
Declaration's internalContext(). The other kind stores the imported
IndexedDUContext directly. There are two circumstances in which a
DUContext::Import will be of the former type instead of the latter: If
it's a specialization, or if the import is in another TopDUContext.
Now before I question the logic, I will pose the actual problem...
When a FunctionDeclaration is created, its internalContext is first
set to it's argument context, if it's later found to be a definition
too, the expression context will import the argument context and then
the FunctionDeclaration's internalContext will be set to the
expression context instead. This means that the only access the
FunctionDefinition has to it's argument context is through digging
through the imports of its InternalContext. Now meet the expression
context of a specialization function. It stores imports via
DeclarationId, the DeclarationId pointing to the FunctionDefinition,
the FunctionDefinition that just switched it's internalContext to
point to its expression context. So then the expression context asks
for what used to be an Import pointing to the argument context, and
the FunctionDefinition returns its expression context, so it appears
to import itself, leading to infinite loops. I fix this by only
allowing it to store a DeclarationId if an import is from a different
TopDUContext and not if it's a specialization.
I'd like to know:
a. It's clear that a TopDUContext could be refreshed and references
destroyed... but under what circumstances should the specialization
context be lost?
b. If it's necessary to store specialized context imports via
DeclarationId, how can it be handled in this case? It seems that an
Import would have to know what kind of context it's importing, and
AbstractFunctionDeclaration would have have a direct reference to it's
argument context in order to support this... rather expensive
memory-wise for an edge case perhaps.




More information about the KDevelop-devel mailing list