Initial implementation of parsing, semantic analysis, and template
instantiation for C++ typename-specifiers such as

  typename T::type

The parsing of typename-specifiers is relatively easy thanks to
annotation tokens. When we see the "typename", we parse the
typename-specifier and produce a typename annotation token. There are
only a few places where we need to handle this. We currently parse the
typename-specifier form that terminates in an identifier, but not the
simple-template-id form, e.g.,

  typename T::template apply<U, V>

Parsing of nested-name-specifiers has a similar problem, since at this
point we don't have any representation of a class template
specialization whose template-name is unknown.

Semantic analysis is only partially complete, with some support for
template instantiation that works for simple examples. 



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@67875 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index e433769..2956460 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1411,6 +1411,32 @@
   return QualType(T, 0);
 }
 
+QualType ASTContext::getTypenameType(NestedNameSpecifier *NNS, 
+                                     const IdentifierInfo *Name,
+                                     QualType Canon) {
+  assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+
+  if (Canon.isNull()) {
+    NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+    if (CanonNNS != NNS)
+      Canon = getTypenameType(CanonNNS, Name);
+  }
+
+  llvm::FoldingSetNodeID ID;
+  TypenameType::Profile(ID, NNS, Name);
+
+  void *InsertPos = 0;
+  TypenameType *T 
+    = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (T)
+    return QualType(T, 0);
+
+  T = new (*this) TypenameType(NNS, Name, Canon);
+  Types.push_back(T);
+  TypenameTypes.InsertNode(T, InsertPos);
+  return QualType(T, 0);  
+}
+
 /// CmpProtocolNames - Comparison predicate for sorting protocols
 /// alphabetically.
 static bool CmpProtocolNames(const ObjCProtocolDecl *LHS,
@@ -1582,6 +1608,46 @@
                               VAT->getIndexTypeQualifier());
 }
 
+NestedNameSpecifier *
+ASTContext::getCanonicalNestedNameSpecifier(NestedNameSpecifier *NNS) {
+  if (!NNS) 
+    return 0;
+
+  switch (NNS->getKind()) {
+  case NestedNameSpecifier::Identifier:
+    // Canonicalize the prefix but keep the identifier the same.
+    return NestedNameSpecifier::Create(*this, 
+                         getCanonicalNestedNameSpecifier(NNS->getPrefix()),
+                                       NNS->getAsIdentifier());
+
+  case NestedNameSpecifier::Namespace:
+    // A namespace is canonical; build a nested-name-specifier with
+    // this namespace and no prefix.
+    return NestedNameSpecifier::Create(*this, 0, NNS->getAsNamespace());
+
+  case NestedNameSpecifier::TypeSpec:
+  case NestedNameSpecifier::TypeSpecWithTemplate: {
+    QualType T = getCanonicalType(QualType(NNS->getAsType(), 0));
+    NestedNameSpecifier *Prefix = 0;
+
+    // FIXME: This isn't the right check!
+    if (T->isDependentType())
+      Prefix = getCanonicalNestedNameSpecifier(NNS->getPrefix());
+
+    return NestedNameSpecifier::Create(*this, Prefix, 
+                 NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate, 
+                                       T.getTypePtr());
+  }
+
+  case NestedNameSpecifier::Global:
+    // The global specifier is canonical and unique.
+    return NNS;
+  }
+
+  // Required to silence a GCC warning
+  return 0;
+}
+
 
 const ArrayType *ASTContext::getAsArrayType(QualType T) {
   // Handle the non-qualified case efficiently.
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 62e972e..40efe2a 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -17,6 +17,7 @@
 #include "clang/AST/Type.h"
 #include "llvm/Support/raw_ostream.h"
 #include <cassert>
+#include <stdio.h>
 
 using namespace clang;
 
@@ -150,3 +151,12 @@
   this->~NestedNameSpecifier();
   Context.Deallocate((void *)this);
 }
+
+void NestedNameSpecifier::Dump() {
+  std::string Result;
+  {
+    llvm::raw_string_ostream OS(Result);
+    Print(OS);
+  }
+  fprintf(stderr, "%s", Result.c_str());
+}
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 103c0a9..0a3e8f9 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1435,6 +1435,22 @@
     InnerString = MyString + ' ' + InnerString;
 }
 
+void TypenameType::getAsStringInternal(std::string &InnerString) const {
+  std::string MyString;
+
+  {
+    llvm::raw_string_ostream OS(MyString);
+    OS << "typename ";
+    NNS->Print(OS);
+    OS << Name->getName();
+  }
+  
+  if (InnerString.empty())
+    InnerString.swap(MyString);
+  else
+    InnerString = MyString + ' ' + 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 4490847..4f0334f 100644
--- a/lib/AST/TypeSerialization.cpp
+++ b/lib/AST/TypeSerialization.cpp
@@ -431,6 +431,19 @@
 }
 
 //===----------------------------------------------------------------------===//
+// TypenameType
+//===----------------------------------------------------------------------===//
+void TypenameType::EmitImpl(llvm::Serializer& S) const {
+  // FIXME: Serialize the actual components
+}
+
+Type* 
+TypenameType::CreateImpl(ASTContext& Context, llvm::Deserializer& D) {
+  // FIXME: Implement de-serialization
+  return 0;
+}
+
+//===----------------------------------------------------------------------===//
 // VariableArrayType
 //===----------------------------------------------------------------------===//