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/Sema/Sema.h b/lib/Sema/Sema.h
index ac260c2..8dee4f1 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -1790,6 +1790,20 @@
   bool CheckTemplateDeclScope(Scope *S, 
                               MultiTemplateParamsArg &TemplateParameterLists);
 
+  /// \brief Called when the parser has parsed a C++ typename
+  /// specifier, e.g., "typename T::type".
+  ///
+  /// \param TypenameLoc the location of the 'typename' keyword
+  /// \param SS the nested-name-specifier following the typename (e.g., 'T::').
+  /// \param II the identifier we're retrieving (e.g., 'type' in the example).
+  /// \param IdLoc the location of the identifier.
+  virtual TypeResult
+  ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+                    const IdentifierInfo &II, SourceLocation IdLoc);
+  QualType CheckTypenameType(NestedNameSpecifier *NNS,
+                             const IdentifierInfo &II,
+                             SourceRange Range);
+                             
   //===--------------------------------------------------------------------===//
   // C++ Template Instantiation
   //
diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp
index 8fb2811..a879989 100644
--- a/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/lib/Sema/SemaCXXScopeSpec.cpp
@@ -127,17 +127,20 @@
     if (TypeDecl *Type = dyn_cast<TypeDecl>(SD)) {
       // Determine whether we have a class (or, in C++0x, an enum) or
       // a typedef thereof. If so, build the nested-name-specifier.
-      QualType T;
-      if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
+      QualType T = Context.getTypeDeclType(Type);
+      bool AcceptableType = false;
+      if (T->isDependentType())
+        AcceptableType = true;
+      else if (TypedefDecl *TD = dyn_cast<TypedefDecl>(SD)) {
         if (TD->getUnderlyingType()->isRecordType() ||
             (getLangOptions().CPlusPlus0x && 
              TD->getUnderlyingType()->isEnumeralType()))
-          T = Context.getTypeDeclType(TD);
+          AcceptableType = true;
       } else if (isa<RecordDecl>(Type) || 
                  (getLangOptions().CPlusPlus0x && isa<EnumDecl>(Type)))
-        T = Context.getTypeDeclType(Type);
+        AcceptableType = true;
 
-      if (!T.isNull())
+      if (AcceptableType)
         return NestedNameSpecifier::Create(Context, Prefix, false, 
                                            T.getTypePtr());
     }
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index 697582c..6994697 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -1964,3 +1964,84 @@
   CurContext->addDecl(Specialization);
   return Specialization;
 }
+
+Sema::TypeResult
+Sema::ActOnTypenameType(SourceLocation TypenameLoc, const CXXScopeSpec &SS,
+                        const IdentifierInfo &II, SourceLocation IdLoc) {
+  NestedNameSpecifier *NNS 
+    = static_cast<NestedNameSpecifier *>(SS.getScopeRep());
+  if (!NNS)
+    return true;
+
+  QualType T = CheckTypenameType(NNS, II, SourceRange(TypenameLoc, IdLoc));
+  if (T.isNull())
+    return 0;
+
+  return T.getAsOpaquePtr();
+}
+
+/// \brief Build the type that describes a C++ typename specifier,
+/// e.g., "typename T::type".
+QualType
+Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II,
+                        SourceRange Range) {
+  if (NNS->isDependent()) // FIXME: member of the current instantiation!
+    return Context.getTypenameType(NNS, &II);
+
+  CXXScopeSpec SS;
+  SS.setScopeRep(NNS);
+  SS.setRange(Range);
+  if (RequireCompleteDeclContext(SS))
+    return QualType();
+
+  DeclContext *Ctx = computeDeclContext(SS);
+  assert(Ctx && "No declaration context?");
+
+  DeclarationName Name(&II);
+  LookupResult Result = LookupQualifiedName(Ctx, Name, LookupOrdinaryName, 
+                                            false);
+  unsigned DiagID = 0;
+  Decl *Referenced = 0;
+  switch (Result.getKind()) {
+  case LookupResult::NotFound:
+    if (Ctx->isTranslationUnit())
+      DiagID = diag::err_typename_nested_not_found_global;
+    else
+      DiagID = diag::err_typename_nested_not_found;
+    break;
+
+  case LookupResult::Found:
+    if (TypeDecl *Type = dyn_cast<TypeDecl>(Result.getAsDecl())) {
+      // We found a type. Build a QualifiedNameType, since the
+      // typename-specifier was just sugar. FIXME: Tell
+      // QualifiedNameType that it has a "typename" prefix.
+      return Context.getQualifiedNameType(NNS, Context.getTypeDeclType(Type));
+    }
+
+    DiagID = diag::err_typename_nested_not_type;
+    Referenced = Result.getAsDecl();
+    break;
+
+  case LookupResult::FoundOverloaded:
+    DiagID = diag::err_typename_nested_not_type;
+    Referenced = *Result.begin();
+    break;
+
+  case LookupResult::AmbiguousBaseSubobjectTypes:
+  case LookupResult::AmbiguousBaseSubobjects:
+  case LookupResult::AmbiguousReference:
+    DiagnoseAmbiguousLookup(Result, Name, Range.getEnd(), Range);
+    return QualType();
+  }
+
+  // If we get here, it's because name lookup did not find a
+  // type. Emit an appropriate diagnostic and return an error.
+  if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx))
+    Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx;
+  else
+    Diag(Range.getEnd(), DiagID) << Range << Name;
+  if (Referenced)
+    Diag(Referenced->getLocation(), diag::note_typename_refers_here)
+      << Name;
+  return QualType();
+}
diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp
index 52f87b9..b274f87 100644
--- a/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/lib/Sema/SemaTemplateInstantiate.cpp
@@ -485,8 +485,23 @@
 TemplateTypeInstantiator::
 InstantiateQualifiedNameType(const QualifiedNameType *T, 
                              unsigned Quals) const {
-  assert(false && "Cannot have dependent qualified name types (yet)");
-  return QualType();
+  // When we instantiated a qualified name type, there's no point in
+  // keeping the qualification around in the instantiated result. So,
+  // just instantiate the named type.
+  return (*this)(T->getNamedType());
+}
+
+QualType 
+TemplateTypeInstantiator::
+InstantiateTypenameType(const TypenameType *T, unsigned Quals) const {
+  NestedNameSpecifier *NNS 
+    = SemaRef.InstantiateNestedNameSpecifier(T->getQualifier(), 
+                                             SourceRange(Loc),
+                                             TemplateArgs, NumTemplateArgs);
+  if (!NNS)
+    return QualType();
+
+  return SemaRef.CheckTypenameType(NNS, *T->getName(), SourceRange(Loc));
 }
 
 QualType 
@@ -799,21 +814,29 @@
     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())
       return 0;
 
-    // Note that T.getTypePtr(), below, strips cv-qualifiers. This is
-    // perfectly reasonable, since cv-qualified types in
-    // nested-name-specifiers don't matter.
-    // FIXME: we need to perform more checking on this type.
-    return NestedNameSpecifier::Create(Context, Prefix, 
+    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.
+      return NestedNameSpecifier::Create(Context, Prefix, 
                  NNS->getKind() == NestedNameSpecifier::TypeSpecWithTemplate,
-                                       T.getTypePtr());
+                                         T.getTypePtr());
+    }
+
+    Diag(Range.getBegin(), diag::err_nested_name_spec_non_tag) << T;
+    return 0;
   }
   }
 
-  // Required to silence GCC warning.
+  // Required to silence a GCC warning
   return 0;
 }