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/ASTContext.cpp b/lib/AST/ASTContext.cpp
index a87a902..72aef42 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1220,6 +1220,34 @@
return QualType(TypeParm, 0);
}
+QualType
+ASTContext::getClassTemplateSpecializationType(TemplateDecl *Template,
+ unsigned NumArgs,
+ uintptr_t *Args, bool *ArgIsType,
+ QualType Canon) {
+ llvm::FoldingSetNodeID ID;
+ ClassTemplateSpecializationType::Profile(ID, Template, NumArgs, Args,
+ ArgIsType);
+ void *InsertPos = 0;
+ ClassTemplateSpecializationType *Spec
+ = ClassTemplateSpecializationTypes.FindNodeOrInsertPos(ID, InsertPos);
+
+ if (Spec)
+ return QualType(Spec, 0);
+
+ void *Mem = Allocate(sizeof(ClassTemplateSpecializationType) +
+ (sizeof(uintptr_t) *
+ (ClassTemplateSpecializationType::
+ getNumPackedWords(NumArgs) +
+ NumArgs)), 8);
+ Spec = new (Mem) ClassTemplateSpecializationType(Template, NumArgs, Args,
+ ArgIsType, Canon);
+ Types.push_back(Spec);
+ ClassTemplateSpecializationTypes.InsertNode(Spec, InsertPos);
+
+ return QualType(Spec, 0);
+}
+
/// CmpProtocolNames - Comparison predicate for sorting protocols
/// alphabetically.
static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
diff --git a/lib/AST/DeclTemplate.cpp b/lib/AST/DeclTemplate.cpp
index d005ca3..ab5a3bc 100644
--- a/lib/AST/DeclTemplate.cpp
+++ b/lib/AST/DeclTemplate.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "clang/Basic/IdentifierTable.h"
#include "llvm/ADT/STLExtras.h"
@@ -43,6 +44,11 @@
NumParams, RAngleLoc);
}
+void TemplateArg::Destroy(ASTContext &C) {
+ if (Kind == ExprArg)
+ getAsExpr()->Destroy(C);
+}
+
//===----------------------------------------------------------------------===//
// TemplateDecl Implementation
//===----------------------------------------------------------------------===//
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;
diff --git a/lib/AST/TypeSerialization.cpp b/lib/AST/TypeSerialization.cpp
index 57598d3..90bc67a 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -13,6 +13,7 @@
#include "clang/AST/Type.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/DeclTemplate.h"
#include "clang/AST/Expr.h"
#include "clang/AST/ASTContext.h"
#include "llvm/Bitcode/Serialize.h"
@@ -377,6 +378,48 @@
}
//===----------------------------------------------------------------------===//
+// ClassTemplateSpecializationType
+//===----------------------------------------------------------------------===//
+
+void ClassTemplateSpecializationType::EmitImpl(Serializer& S) const {
+ S.Emit(getCanonicalTypeInternal());
+ S.EmitPtr(Template);
+ S.EmitInt(NumArgs);
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ S.EmitBool(isArgType(Arg));
+ if (isArgType(Arg))
+ S.Emit(getArgAsType(Arg));
+ else
+ S.EmitOwnedPtr(getArgAsExpr(Arg));
+ }
+}
+
+Type*
+ClassTemplateSpecializationType::
+CreateImpl(ASTContext& Context, Deserializer& D) {
+ llvm::SmallVector<uintptr_t, 16> Args;
+ llvm::SmallVector<bool, 16> ArgIsType;
+
+ QualType Canon = QualType::ReadVal(D);
+ TemplateDecl *Template = cast<TemplateDecl>(D.ReadPtr<Decl>());
+ unsigned NumArgs = D.ReadInt();
+
+ for (unsigned Arg = 0; Arg < NumArgs; ++Arg) {
+ bool IsType = D.ReadBool();
+ ArgIsType.push_back(IsType);
+ if (IsType)
+ Args.push_back(
+ reinterpret_cast<uintptr_t>(QualType::ReadVal(D).getAsOpaquePtr()));
+ else
+ Args.push_back(reinterpret_cast<uintptr_t>(D.ReadOwnedPtr<Expr>(Context)));
+ }
+
+ return Context.getClassTemplateSpecializationType(Template, NumArgs,
+ &Args[0], &ArgIsType[0],
+ Canon).getTypePtr();
+}
+
+//===----------------------------------------------------------------------===//
// VariableArrayType
//===----------------------------------------------------------------------===//