Improve parser recovery when we encounter a dependent template name
that is missing the 'template' keyword, e.g., 

  t->getAs<T>()

where getAs is a member of an unknown specialization. C++ requires
that we treat "getAs" as a value, but that would fail to parse since T
is the name of a type. We would then fail at the '>', since a type
cannot be followed by a '>'.

This is a very common error for C++ programmers to make, especially
since GCC occasionally allows it when it shouldn't (as does Visual
C++). So, when we are in this case, we use tentative parsing to see if
the tokens starting at "<" can only be parsed as a template argument
list. If so, we produce a diagnostic with a fix-it that states that
the 'template' keyword is needed:

test/SemaTemplate/dependent-template-recover.cpp:5:8: error: 'template' keyword
      is required to treat 'getAs' as a dependent template name
    t->getAs<T>();
       ^
       template 

This is just a start of this patch; I'd like to apply the same
approach to everywhere that a template-id with dependent template name
can be parsed.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@104406 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index b7ccea5..1588b69 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -289,11 +289,13 @@
       TemplateTy Template;
       UnqualifiedId TemplateName;
       TemplateName.setIdentifier(&II, Tok.getLocation());
+      bool MemberOfUnknownSpecialization;
       if (TemplateNameKind TNK = Actions.isTemplateName(CurScope, SS, 
                                                         TemplateName,
                                                         ObjectType,
                                                         EnteringContext,
-                                                        Template)) {
+                                                        Template,
+                                              MemberOfUnknownSpecialization)) {
         // We have found a template name, so annotate this this token
         // with a template-id annotation. We do not permit the
         // template-id to be translated into a type annotation,
@@ -990,21 +992,54 @@
       TNK = TNK_Dependent_template_name;
       if (!Template.get())
         return true;      
-    } else 
+    } else {
+      bool MemberOfUnknownSpecialization;
       TNK = Actions.isTemplateName(CurScope, SS, Id, ObjectType, 
-                                   EnteringContext, Template);
+                                   EnteringContext, Template,
+                                   MemberOfUnknownSpecialization);
+      
+      if (TNK == TNK_Non_template && MemberOfUnknownSpecialization &&
+          ObjectType && IsTemplateArgumentList()) {
+        // We have something like t->getAs<T>(), where getAs is a 
+        // member of an unknown specialization. However, this will only
+        // parse correctly as a template, so suggest the keyword 'template'
+        // before 'getAs' and treat this as a dependent template name.
+        std::string Name;
+        if (Id.getKind() == UnqualifiedId::IK_Identifier)
+          Name = Id.Identifier->getName();
+        else {
+          Name = "operator ";
+          if (Id.getKind() == UnqualifiedId::IK_OperatorFunctionId)
+            Name += getOperatorSpelling(Id.OperatorFunctionId.Operator);
+          else
+            Name += Id.Identifier->getName();
+        }
+        Diag(Id.StartLocation, diag::err_missing_dependent_template_keyword)
+          << Name
+          << FixItHint::CreateInsertion(Id.StartLocation, "template ");
+        Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, 
+                                                      Id, ObjectType,
+                                                      EnteringContext);
+        TNK = TNK_Dependent_template_name;
+        if (!Template.get())
+          return true;              
+      }
+    }
     break;
       
   case UnqualifiedId::IK_ConstructorName: {
     UnqualifiedId TemplateName;
+    bool MemberOfUnknownSpecialization;
     TemplateName.setIdentifier(Name, NameLoc);
     TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, 
-                                 EnteringContext, Template);
+                                 EnteringContext, Template,
+                                 MemberOfUnknownSpecialization);
     break;
   }
       
   case UnqualifiedId::IK_DestructorName: {
     UnqualifiedId TemplateName;
+    bool MemberOfUnknownSpecialization;
     TemplateName.setIdentifier(Name, NameLoc);
     if (ObjectType) {
       Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, 
@@ -1015,7 +1050,8 @@
         return true;
     } else {
       TNK = Actions.isTemplateName(CurScope, SS, TemplateName, ObjectType, 
-                                   EnteringContext, Template);
+                                   EnteringContext, Template,
+                                   MemberOfUnknownSpecialization);
       
       if (TNK == TNK_Non_template && Id.DestructorName == 0) {
         Diag(NameLoc, diag::err_destructor_template_id)