Parsing, semantic analysis, and template instantiation for typename
specifiers that terminate in a simple-template-id, e.g.,

  typename MetaFun::template apply<T1, T2>

Also, implement template instantiation for dependent
nested-name-specifiers that involve unresolved identifiers, e.g.,

  typename T::type::type





git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68166 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp
index 422988d..cede0e5 100644
--- a/lib/AST/ASTContext.cpp
+++ b/lib/AST/ASTContext.cpp
@@ -1454,6 +1454,39 @@
   return QualType(T, 0);  
 }
 
+QualType 
+ASTContext::getTypenameType(NestedNameSpecifier *NNS, 
+                            const TemplateSpecializationType *TemplateId,
+                            QualType Canon) {
+  assert(NNS->isDependent() && "nested-name-specifier must be dependent");
+
+  if (Canon.isNull()) {
+    NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+    QualType CanonType = getCanonicalType(QualType(TemplateId, 0));
+    if (CanonNNS != NNS || CanonType != QualType(TemplateId, 0)) {
+      const TemplateSpecializationType *CanonTemplateId
+        = CanonType->getAsTemplateSpecializationType();
+      assert(CanonTemplateId &&
+             "Canonical type must also be a template specialization type");
+      Canon = getTypenameType(CanonNNS, CanonTemplateId);
+    }
+  }
+
+  llvm::FoldingSetNodeID ID;
+  TypenameType::Profile(ID, NNS, TemplateId);
+
+  void *InsertPos = 0;
+  TypenameType *T 
+    = TypenameTypes.FindNodeOrInsertPos(ID, InsertPos);
+  if (T)
+    return QualType(T, 0);
+
+  T = new (*this) TypenameType(NNS, TemplateId, 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,
diff --git a/lib/AST/NestedNameSpecifier.cpp b/lib/AST/NestedNameSpecifier.cpp
index 2db8c76..c94a4da 100644
--- a/lib/AST/NestedNameSpecifier.cpp
+++ b/lib/AST/NestedNameSpecifier.cpp
@@ -30,7 +30,7 @@
   NestedNameSpecifier *NNS 
     = Context.NestedNameSpecifiers.FindNodeOrInsertPos(ID, InsertPos);
   if (!NNS) {
-    NNS = new (Context) NestedNameSpecifier(Mockup);
+    NNS = new (Context, 4) NestedNameSpecifier(Mockup);
     Context.NestedNameSpecifiers.InsertNode(NNS, InsertPos);
   }
 
@@ -44,9 +44,9 @@
   assert(Prefix && Prefix->isDependent() && "Prefix must be dependent");
 
   NestedNameSpecifier Mockup;
-  Mockup.Prefix = Prefix;
-  Mockup.Specifier.setPointer(II);
-  Mockup.Specifier.setInt(Identifier);
+  Mockup.Prefix.setPointer(Prefix);
+  Mockup.Prefix.setInt(Identifier);
+  Mockup.Specifier = II;
   return FindOrInsert(Context, Mockup);
 }
 
@@ -58,9 +58,9 @@
           (Prefix->getAsType() == 0 && Prefix->getAsIdentifier() == 0)) &&
          "Broken nested name specifier");
   NestedNameSpecifier Mockup;
-  Mockup.Prefix = Prefix;
-  Mockup.Specifier.setPointer(NS);
-  Mockup.Specifier.setInt(Namespace);
+  Mockup.Prefix.setPointer(Prefix);
+  Mockup.Prefix.setInt(Namespace);
+  Mockup.Specifier = NS;
   return FindOrInsert(Context, Mockup);
 }
 
@@ -69,15 +69,15 @@
                             bool Template, Type *T) {
   assert(T && "Type cannot be NULL");
   NestedNameSpecifier Mockup;
-  Mockup.Prefix = Prefix;
-  Mockup.Specifier.setPointer(T);
-  Mockup.Specifier.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+  Mockup.Prefix.setPointer(Prefix);
+  Mockup.Prefix.setInt(Template? TypeSpecWithTemplate : TypeSpec);
+  Mockup.Specifier = T;
   return FindOrInsert(Context, Mockup);
 }
   
 NestedNameSpecifier *NestedNameSpecifier::GlobalSpecifier(ASTContext &Context) {
   if (!Context.GlobalNestedNameSpecifier)
-    Context.GlobalNestedNameSpecifier = new (Context) NestedNameSpecifier();
+    Context.GlobalNestedNameSpecifier = new (Context, 4) NestedNameSpecifier();
   return Context.GlobalNestedNameSpecifier;
 }
 
@@ -105,8 +105,8 @@
 /// \brief Print this nested name specifier to the given output
 /// stream.
 void NestedNameSpecifier::print(llvm::raw_ostream &OS) const {
-  if (Prefix)
-    Prefix->print(OS);
+  if (getPrefix())
+    getPrefix()->print(OS);
 
   switch (getKind()) {
   case Identifier:
diff --git a/lib/AST/TemplateName.cpp b/lib/AST/TemplateName.cpp
index 659796d..16b96a0 100644
--- a/lib/AST/TemplateName.cpp
+++ b/lib/AST/TemplateName.cpp
@@ -38,16 +38,18 @@
   return true;
 }
 
-void TemplateName::print(llvm::raw_ostream &OS) const {
+void TemplateName::print(llvm::raw_ostream &OS, bool SuppressNNS) const {
   if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
     OS << Template->getIdentifier()->getName();
   else if (QualifiedTemplateName *QTN = getAsQualifiedTemplateName()) {
-    QTN->getQualifier()->print(OS);
+    if (!SuppressNNS)
+      QTN->getQualifier()->print(OS);
     if (QTN->hasTemplateKeyword())
       OS << "template ";
     OS << QTN->getTemplateDecl()->getIdentifier()->getName();
   } else if (DependentTemplateName *DTN = getAsDependentTemplateName()) {
-    DTN->getQualifier()->print(OS);
+    if (!SuppressNNS)
+      DTN->getQualifier()->print(OS);
     OS << "template ";
     OS << DTN->getName()->getName();
   }
diff --git a/lib/AST/Type.cpp b/lib/AST/Type.cpp
index 669eb7c..b9bd0ba 100644
--- a/lib/AST/Type.cpp
+++ b/lib/AST/Type.cpp
@@ -1450,7 +1450,14 @@
     llvm::raw_string_ostream OS(MyString);
     OS << "typename ";
     NNS->print(OS);
-    OS << Name->getName();
+
+    if (const IdentifierInfo *Ident = getIdentifier())
+      OS << Ident->getName();
+    else if (const TemplateSpecializationType *Spec = getTemplateId()) {
+      Spec->getTemplateName().print(OS, true);
+      OS << TemplateSpecializationType::PrintTemplateArgumentList(
+                                         Spec->getArgs(), Spec->getNumArgs());
+    }
   }
   
   if (InnerString.empty())
diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp
index 56e217a..17eca37 100644
--- a/lib/Parse/Parser.cpp
+++ b/lib/Parse/Parser.cpp
@@ -828,7 +828,7 @@
     //   typename-specifier:
     //     'typename' '::' [opt] nested-name-specifier identifier
     //     'typename' '::' [opt] nested-name-specifier template [opt] 
-    //            simple-template-id  [TODO]
+    //            simple-template-id
     SourceLocation TypenameLoc = ConsumeToken();
     CXXScopeSpec SS;
     bool HadNestedNameSpecifier = ParseOptionalCXXScopeSpecifier(SS);
@@ -842,16 +842,35 @@
       // FIXME: check whether the next token is '<', first!
       Ty = Actions.ActOnTypenameType(TypenameLoc, SS, *Tok.getIdentifierInfo(), 
                                      Tok.getLocation());
-      // FIXME: better error recovery!
-      Tok.setKind(tok::annot_typename);
-      Tok.setAnnotationValue(Ty.get());
-      Tok.setAnnotationEndLoc(Tok.getLocation());
-      Tok.setLocation(TypenameLoc);
-      PP.AnnotateCachedTokens(Tok);
-      return true;
-    } 
+    } else if (Tok.is(tok::annot_template_id)) {
+      TemplateIdAnnotation *TemplateId 
+        = static_cast<TemplateIdAnnotation *>(Tok.getAnnotationValue());
+      if (TemplateId->Kind == TNK_Function_template) {
+        Diag(Tok, diag::err_typename_refers_to_non_type_template)
+          << Tok.getAnnotationRange();
+        return false;
+      }
 
-    return false;
+      if (AnnotateTemplateIdTokenAsType(0))
+        return false;
+
+      assert(Tok.is(tok::annot_typename) && 
+             "AnnotateTemplateIdTokenAsType isn't working properly");
+      Ty = Actions.ActOnTypenameType(TypenameLoc, SS, SourceLocation(),
+                                     Tok.getAnnotationValue());
+    } else {
+      Diag(Tok, diag::err_expected_type_name_after_typename)
+        << SS.getRange();
+      return false;
+    }
+
+    // FIXME: better error recovery!
+    Tok.setKind(tok::annot_typename);
+    Tok.setAnnotationValue(Ty.get());
+    Tok.setAnnotationEndLoc(Tok.getLocation());
+    Tok.setLocation(TypenameLoc);
+    PP.AnnotateCachedTokens(Tok);
+    return true;
   }
 
   CXXScopeSpec SS;
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index 3a18f96..7f68636 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1816,6 +1816,19 @@
   virtual TypeResult
   ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
                     const IdentifierInfo &II, SourceLocation IdLoc);
+
+  /// \brief Called when the parser has parsed a C++ typename
+  /// specifier that ends in a template-id, e.g., 
+  /// "typename MetaFun::template apply<T1, T2>".
+  ///
+  /// \param TypenameLoc the location of the 'typename' keyword
+  /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+  /// \param TemplateLoc the location of the 'template' keyword, if any.
+  /// \param Ty the type that the typename specifier refers to.
+  virtual TypeResult
+  ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+                    SourceLocation TemplateLoc, TypeTy *Ty);
+
   QualType CheckTypenameType(NestedNameSpecifier *NNS,
                              const IdentifierInfo &II,
                              SourceRange Range);
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 591f323..5db19a5 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -2105,6 +2105,22 @@
   return T.getAsOpaquePtr();
 }
 
+Sema::TypeResult
+Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+                        SourceLocation TemplateLoc, TypeTy *Ty) {
+  QualType T = QualType::getFromOpaquePtr(Ty);
+  NestedNameSpecifier *NNS 
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  const TemplateSpecializationType *TemplateId 
+    = T->getAsTemplateSpecializationType();
+  assert(TemplateId && "Expected a template specialization type");
+
+  if (NNS->isDependent())
+    return Context.getTypenameType(NNS, TemplateId).getAsOpaquePtr();
+
+  return Context.getQualifiedNameType(NNS, T).getAsOpaquePtr();
+}
+
 /// \brief Build the type that describes a C++ typename specifier,
 /// e.g., "typename T::type".
 QualType
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 2f12716..a041d06 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -497,6 +497,15 @@
 QualType 
 TemplateTypeInstantiator::
 InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
+  if (const TemplateSpecializationType *TemplateId = T->getTemplateId()) {
+    // When the typename type refers to a template-id, the template-id
+    // is dependent and has enough information to instantiate the
+    // result of the typename type. Since we don't care about keeping
+    // the spelling of the typename type in template instantiations,
+    // we just instantiate the template-id.
+    return InstantiateTemplateSpecializationType(TemplateId, Quals);
+  }
+
   NestedNameSpecifier *NNS 
     = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), 
                                              SourceRange(Loc),
@@ -504,7 +513,7 @@
   if (!NNS)
     return QualType();
 
-  return SemaRef.CheckTypenameType(NNS, *T->getName(), SourceRange(Loc));
+  return SemaRef.CheckTypenameType(NNS, *T->getIdentifier(), SourceRange(Loc));
 }
 
 QualType 
@@ -801,10 +810,20 @@
   }
 
   switch (NNS->getKind()) {
-  case NestedNameSpecifier::Identifier:
-    // FIXME: Implement this lookup!
-    assert(false && "Cannot instantiate this nested-name-specifier");
+  case NestedNameSpecifier::Identifier: {
+    assert(Prefix && 
+           "Can't have an identifier nested-name-specifier with no prefix");
+    CXXScopeSpec SS;
+    // FIXME: The source location information is all wrong.
+    SS.setRange(Range);
+    SS.setScopeRep(Prefix);
+    return static_cast<NestedNameSpecifier *>(
+                                 ActOnCXXNestedNameSpecifier(0, SS,
+                                                             Range.getEnd(),
+                                                             Range.getEnd(),
+                                                   *NNS->getAsIdentifier()));
     break;
+  }
 
   case NestedNameSpecifier::Namespace:
   case NestedNameSpecifier::Global:
@@ -816,9 +835,6 @@
     if (!T->isDependentType())
       return NNS;
 
-    // FIXME: We won't be able to perform the instantiation here when
-    // the template-name is dependent, e.g., we have something like
-    // "T::template apply<U>::type".
     T = InstantiateType(T, TemplateArgs, NumTemplateArgs, Range.getBegin(),
                         DeclarationName());
     if (T.isNull())
@@ -826,9 +842,7 @@
 
     if (T->isRecordType() ||
         (getLangOptions().CPlusPlus0x && T->isEnumeralType())) {
-      // Note that T.getTypePtr(), below, strips cv-qualifiers. This is
-      // perfectly reasonable, since cv-qualified types in
-      // nested-name-specifiers don't matter.
+      assert(T.getCVRQualifiers() == 0 && "Can't get cv-qualifiers here");
       return NestedNameSpecifier::Create(Context, Prefix, 
                  NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
                                          T.getTypePtr());