Hello.
We were looking into these three AST classes (while wearing the glasses
of applications working at the source code level) and we ended up with
the following picture:
1) An ElaboratedType is a type name prefixed by a tag keyword.
The current clang implementation requires that this tag keyword is taken
from the set { struct, class, union, enum }. This differs from the
standard (C++98 7.1.5.3), where also the keyword 'typename' is allowed.
The (optional) name qualifier is not directly encoded in the AST node.
The C++98/03 standard is very, very confusing here. The intent was not to make 'typename' abide by the rules in 7.1.5.3 [dcl.type.elab]; it was a syntactic convenience in the grammar.
I suggest that you instead look at C++0x, which has a "typename-specifier" grammar production for typename types that is completely distinct from elaborated-type-specifiers.
2) A QualifiedNameType is a non-dependent type name provided with a
(mandatory) name qualifier. The current implementation does not encode
the (optional) tag keyword, but there is a FIXME noting that, e.g., the
'typename' keyword could be used even though the name is not dependent
(C++98 14.6p5).
The intent of QualifiedNameType is that it never have a tag; that should be handled by ElaboratedType.
3) A TypenameType is a dependent type name provided with a (mandatory)
name qualifier. The current implementation does not encode the
(mandatory) tag keyword, which will be tipically be 'typename', but
could also be another one, as in the following example:
[snip]
We would like to improve things in order to have an exact picture of
what was written in the program. We have two options:
A) allow for 'typename' in ElaboratedType and let these keywords be
*always* encoded by ElaboratedType nodes. That is, variable x1, x2, y1
and y2 will all have ElaboratedType, containing a TypenameType (x1 and
y1) or a QualifiedNameType (x2 and y2). One may also consider the
possibility of renaming class "TypenameType" to become
"DependentNameType" (since the typename keyword is not actually implied).
B) get rid of ElaboratedType nodes and push the corresponding info about
the tag keyword down into QualifiedNameType (where the name qualifier
would become optional) and TypenameType.
To our eyes, option A) is closer to what is said in the C++ standard;
however, option B would maybe require less AST nodes (of course, the
inner nodes would become bigger).
What is the opinion of clang developers?
Is there an option C which is even better?
There is an option (C). Here's what I think each of the types should do:
ElaboratedType: Should handle all elaborated-type-specifiers in the C++0x sense, which means a type referenced via the enum/class/struct/union keyword. This class should be extended with an optional NestedNameSpecifier to handle qualified elaborated-type-specifiers, ideally in a implementation-detail base class so that we don't pay a size penalty for "struct X". Getting this right should make fixing PR5681 trivial.
QualifiedNameType: Should handle all type references that involve qualified names but for which we can resolve the name lookup to actually refer to a specific type. These could actually have "typename" qualifiers on them, but the point is that QualifiedNameType is always sugar.
TypenameType: Should handle all type references that involve qualified names where the name it refers to is a dependent name. May or may not actually have the "typename" keyword.
- Doug