Start processing template-ids as types when the template-name refers
to a class template. For example, the template-id 'vector<int>' now
has a nice, sugary type in the type system. What we can do now:
- Parse template-ids like 'vector<int>' (where 'vector' names a
class template) and form proper types for them in the type system.
- Parse icky template-ids like 'A<5>' and 'A<(5 > 0)>' properly,
using (sadly) a bool in the parser to tell it whether '>' should
be treated as an operator or not.
This is a baby-step, with major problems and limitations:
- There are currently two ways that we handle template arguments
(whether they are types or expressions). These will be merged, and,
most likely, TemplateArg will disappear.
- We don't have any notion of the declaration of class template
specializations or of template instantiations, so all template-ids
are fancy names for 'int' :)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64153 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 106d0eb..6ec5062 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -489,6 +489,14 @@
return dyn_cast<TemplateTypeParmType>(CanonicalType);
}
+const ClassTemplateSpecializationType *
+Type::getClassTemplateSpecializationType() const {
+ // There is no sugar for class template specialization types, so
+ // just return the canonical type pointer if it is the right class.
+ return dyn_cast<ClassTemplateSpecializationType>(CanonicalType);
+}
+
+
bool Type::isIntegerType() const {
if (const BuiltinType *BT = dyn_cast<BuiltinType>(CanonicalType))
return BT->getKind() >= BuiltinType::Bool &&
@@ -882,6 +890,54 @@
return isa<EnumDecl>(TT->getDecl());
}
+void
+ClassTemplateSpecializationType::
+packBooleanValues(unsigned NumArgs, bool *Values, uintptr_t *Words) {
+ const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+
+ for (unsigned PW = 0, NumPackedWords = getNumPackedWords(NumArgs), Arg = 0;
+ PW != NumPackedWords; ++PW) {
+ uintptr_t Word = 0;
+ for (unsigned Bit = 0; Bit < BitsPerWord && Arg < NumArgs; ++Bit, ++Arg) {
+ Word <<= 1;
+ Word |= Values[Arg];
+ }
+ Words[PW] = Word;
+ }
+}
+
+ClassTemplateSpecializationType::
+ClassTemplateSpecializationType(TemplateDecl *T, unsigned NumArgs,
+ uintptr_t *Args, bool *ArgIsType,
+ QualType Canon)
+ : Type(ClassTemplateSpecialization, Canon, /*FIXME:Dependent=*/false),
+ Template(T), NumArgs(NumArgs)
+{
+ uintptr_t *Data = reinterpret_cast<uintptr_t *>(this + 1);
+
+ // Pack the argument-is-type values into the words just after the
+ // class template specialization type.
+ packBooleanValues(NumArgs, ArgIsType, Data);
+
+ // Copy the template arguments after the packed words.
+ Data += getNumPackedWords(NumArgs);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg)
+ Data[Arg] = Args[Arg];
+}
+
+uintptr_t
+ClassTemplateSpecializationType::getArgAsOpaqueValue(unsigned Arg) const {
+ const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+ Data += getNumPackedWords(NumArgs);
+ return Data[Arg];
+}
+
+bool ClassTemplateSpecializationType::isArgType(unsigned Arg) const {
+ const unsigned BitsPerWord = sizeof(uintptr_t) * CHAR_BIT;
+ const uintptr_t *Data = reinterpret_cast<const uintptr_t *>(this + 1);
+ Data += Arg / BitsPerWord;
+ return (*Data >> (Arg % BitsPerWord)) & 0x01;
+}
//===----------------------------------------------------------------------===//
// Type Printing
@@ -1146,6 +1202,47 @@
InnerString = Name->getName() + InnerString;
}
+void
+ClassTemplateSpecializationType::
+getAsStringInternal(std::string &InnerString) const {
+ std::string SpecString = Template->getNameAsString();
+ SpecString += '<';
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ if (Arg)
+ SpecString += ", ";
+
+ // Print the argument into a string.
+ std::string ArgString;
+ if (isArgType(Arg))
+ getArgAsType(Arg).getAsStringInternal(ArgString);
+ else {
+ llvm::raw_string_ostream s(ArgString);
+ getArgAsExpr(Arg)->printPretty(s);
+ }
+
+ // If this is the first argument and its string representation
+ // begins with the global scope specifier ('::foo'), add a space
+ // to avoid printing the diagraph '<:'.
+ if (!Arg && !ArgString.empty() && ArgString[0] == ':')
+ SpecString += ' ';
+
+ SpecString += ArgString;
+ }
+
+ // If the last character of our string is '>', add another space to
+ // keep the two '>''s separate tokens. We don't *have* to do this in
+ // C++0x, but it's still good hygiene.
+ if (SpecString[SpecString.size() - 1] == '>')
+ SpecString += ' ';
+
+ SpecString += '>';
+
+ if (InnerString.empty())
+ InnerString.swap(SpecString);
+ else
+ InnerString = SpecString + ' ' + InnerString;
+}
+
void ObjCInterfaceType::getAsStringInternal(std::string &InnerString) const {
if (!InnerString.empty()) // Prefix the basic type, e.g. 'typedefname X'.
InnerString = ' ' + InnerString;