Improve recovery for template-ids whose template-name doesn't actually
name a template, when they occur in a base-specifier. This is one of
the (few) places where we know for sure that an identifier followed by
a '<' must be a template name, so we can diagnose and recover well:

test/SemaTemplate/dependent-base-classes.cpp:9:16: error: missing
'template'
      keyword prior to dependent template name 'T::apply'
struct X1 : T::apply<U> { }; // expected-error{{missing 'template' ...
               ^
               template 
test/SemaTemplate/dependent-base-classes.cpp:12:13: error: unknown
template name
      'vector'
struct X2 : vector<T> { }; // expected-error{{unknown template name
'vector'}}
            ^
2 diagnostics generated.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@93257 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td
index 98a74a5..51b6bff 100644
--- a/include/clang/Basic/DiagnosticParseKinds.td
+++ b/include/clang/Basic/DiagnosticParseKinds.td
@@ -261,6 +261,8 @@
 
 /// C++ Templates
 def err_expected_template : Error<"expected template">;
+def err_unknown_template_name : Error<
+  "unknown template name %0">;
 def err_expected_comma_greater : Error<
   "expected ',' or '>' in template-parameter-list">;
 def err_expected_type_id_after : Error<"expected type-id after '%0'">;
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td
index 82c5544..8fcc97b 100644
--- a/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/include/clang/Basic/DiagnosticSemaKinds.td
@@ -1309,6 +1309,8 @@
     "'%0%1' instantiated to a class template, not a function template">;
 def note_referenced_class_template : Error<
     "class template declared here">;
+def err_template_kw_missing : Error<
+  "missing 'template' keyword prior to dependent template name '%0%1'">;
 
 // C++0x Variadic Templates
 def err_template_param_pack_default_arg : Error<
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h
index be46851..292a2df 100644
--- a/include/clang/Parse/Action.h
+++ b/include/clang/Parse/Action.h
@@ -291,6 +291,42 @@
                                           bool EnteringContext,
                                           TemplateTy &Template) = 0;
 
+  /// \brief Action called as part of error recovery when the parser has 
+  /// determined that the given name must refer to a template, but 
+  /// \c isTemplateName() did not return a result.
+  ///
+  /// This callback permits the action to give a detailed diagnostic when an
+  /// unknown template name is encountered and, potentially, to try to recover
+  /// by producing a new template in \p SuggestedTemplate.
+  ///
+  /// \param II the name that should be a template.
+  ///
+  /// \param IILoc the location of the name in the source.
+  ///
+  /// \param S the scope in which name lookup was performed.
+  ///
+  /// \param SS the C++ scope specifier that preceded the name.
+  ///
+  /// \param SuggestedTemplate if the action sets this template to a non-NULL,
+  /// template, the parser will recover by consuming the template name token
+  /// and the template argument list that follows.
+  ///
+  /// \param SuggestedTemplateKind as input, the kind of template that we
+  /// expect (e.g., \c TNK_Type_template or \c TNK_Function_template). If the
+  /// action provides a suggested template, this should be set to the kind of
+  /// template.
+  ///
+  /// \returns true if a diagnostic was emitted, false otherwise. When false,
+  /// the parser itself will emit a generic "unknown template name" diagnostic.
+  virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, 
+                                           SourceLocation IILoc,
+                                           Scope *S,
+                                           const CXXScopeSpec *SS,
+                                           TemplateTy &SuggestedTemplate,
+                                           TemplateNameKind &SuggestedKind) {
+    return false;
+  }
+  
   /// ActOnCXXGlobalScopeSpecifier - Return the object that represents the
   /// global scope ('::').
   virtual CXXScopeTy *ActOnCXXGlobalScopeSpecifier(Scope *S,
diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp
index 61a4941..90040c5 100644
--- a/lib/Parse/ParseDeclCXX.cpp
+++ b/lib/Parse/ParseDeclCXX.cpp
@@ -490,18 +490,57 @@
     return true;
   }
 
+  IdentifierInfo *Id = Tok.getIdentifierInfo();
+  SourceLocation IdLoc = ConsumeToken();
+
+  if (Tok.is(tok::less)) {
+    // It looks the user intended to write a template-id here, but the
+    // template-name was wrong. Try to fix that.
+    TemplateNameKind TNK = TNK_Type_template;
+    TemplateTy Template;
+    if (!Actions.DiagnoseUnknownTemplateName(*Id, IdLoc, CurScope,
+                                             SS, Template, TNK)) {
+      Diag(IdLoc, diag::err_unknown_template_name)
+        << Id;
+    }
+    
+    if (!Template)
+      return true;
+
+    // Form the template name 
+    UnqualifiedId TemplateName;
+    TemplateName.setIdentifier(Id, IdLoc);
+    
+    // Parse the full template-id, then turn it into a type.
+    if (AnnotateTemplateIdToken(Template, TNK, SS, TemplateName,
+                                SourceLocation(), true))
+      return true;
+    if (TNK == TNK_Dependent_template_name)
+      AnnotateTemplateIdTokenAsType(SS);
+    
+    // If we didn't end up with a typename token, there's nothing more we
+    // can do.
+    if (Tok.isNot(tok::annot_typename))
+      return true;
+    
+    // Retrieve the type from the annotation token, consume that token, and
+    // return.
+    EndLocation = Tok.getAnnotationEndLoc();
+    TypeTy *Type = Tok.getAnnotationValue();
+    ConsumeToken();
+    return Type;
+  }
+
   // We have an identifier; check whether it is actually a type.
-  TypeTy *Type = Actions.getTypeName(*Tok.getIdentifierInfo(),
-                                     Tok.getLocation(), CurScope, SS,
-                                     true);
-  if (!Type) {
-    Diag(Tok, DestrExpected ? diag::err_destructor_class_name
+  TypeTy *Type = Actions.getTypeName(*Id, IdLoc, CurScope, SS, true);
+  if (!Type) {    
+    Diag(IdLoc, DestrExpected ? diag::err_destructor_class_name
                             : diag::err_expected_class_name);
     return true;
   }
 
   // Consume the identifier.
-  EndLocation = ConsumeToken();
+  EndLocation = IdLoc;
   return Type;
 }
 
diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h
index d46bfc6..d06cecc 100644
--- a/lib/Sema/Sema.h
+++ b/lib/Sema/Sema.h
@@ -2367,6 +2367,14 @@
                                           TypeTy *ObjectType,
                                           bool EnteringContext,
                                           TemplateTy &Template);
+  
+  virtual bool DiagnoseUnknownTemplateName(const IdentifierInfo &II, 
+                                           SourceLocation IILoc,
+                                           Scope *S,
+                                           const CXXScopeSpec *SS,
+                                           TemplateTy &SuggestedTemplate,
+                                           TemplateNameKind &SuggestedKind);
+    
   bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
   TemplateDecl *AdjustDeclIfTemplate(DeclPtrTy &Decl);
 
diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp
index d11bf3c..e75277e 100644
--- a/lib/Sema/SemaTemplate.cpp
+++ b/lib/Sema/SemaTemplate.cpp
@@ -143,6 +143,30 @@
   return TemplateKind;
 }
 
+bool Sema::DiagnoseUnknownTemplateName(const IdentifierInfo &II, 
+                                       SourceLocation IILoc,
+                                       Scope *S,
+                                       const CXXScopeSpec *SS,
+                                       TemplateTy &SuggestedTemplate,
+                                       TemplateNameKind &SuggestedKind) {
+  // We can't recover unless there's a dependent scope specifier preceding the
+  // template name.
+  if (!SS || !SS->isSet() || !isDependentScopeSpecifier(*SS) ||
+      computeDeclContext(*SS))
+    return false;
+  
+  // The code is missing a 'template' keyword prior to the dependent template
+  // name.
+  NestedNameSpecifier *Qualifier = (NestedNameSpecifier*)SS->getScopeRep();
+  Diag(IILoc, diag::err_template_kw_missing)
+    << Qualifier << II.getName()
+    << CodeModificationHint::CreateInsertion(IILoc, "template ");
+  SuggestedTemplate 
+    = TemplateTy::make(Context.getDependentTemplateName(Qualifier, &II));
+  SuggestedKind = TNK_Dependent_template_name;
+  return true;
+}
+
 void Sema::LookupTemplateName(LookupResult &Found,
                               Scope *S, const CXXScopeSpec &SS,
                               QualType ObjectType,
diff --git a/test/SemaTemplate/dependent-base-classes.cpp b/test/SemaTemplate/dependent-base-classes.cpp
index 5697920..2427658 100644
--- a/test/SemaTemplate/dependent-base-classes.cpp
+++ b/test/SemaTemplate/dependent-base-classes.cpp
@@ -4,3 +4,9 @@
 struct X0 : T::template apply<U> { 
   X0(U u) : T::template apply<U>(u) { }
 };
+
+template<typename T, typename U>
+struct X1 : T::apply<U> { }; // expected-error{{missing 'template' keyword prior to dependent template name 'T::apply'}}
+
+template<typename T>
+struct X2 : vector<T> { }; // expected-error{{unknown template name 'vector'}}