Teach the type-id/expression disambiguator about different
disambiguation contexts, so that we properly parse template arguments
such as

  A<int()>

as type-ids rather than as expressions. Since this can be confusing
(especially when the template parameter is a non-type template
parameter), we try to give a friendly error message.

Almost, eliminate a redundant error message (that should have been a
note) and add some ultra-basic checks for non-type template
arguments.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64189 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseTentative.cpp b/lib/Parse/ParseTentative.cpp
index 445dd8b..06c136d 100644
--- a/lib/Parse/ParseTentative.cpp
+++ b/lib/Parse/ParseTentative.cpp
@@ -270,16 +270,24 @@
   return TPR == TPResult::True();
 }
 
-/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to
-/// know whether the parens contain an expression or a type-id.
-/// Returns true for a type-id and false for an expression.
-/// If during the disambiguation process a parsing error is encountered,
-/// the function returns true to let the declaration parsing code handle it.
-///
-/// type-id:
-///   type-specifier-seq abstract-declarator[opt]
-///
-bool Parser::isCXXTypeIdInParens() {
+  /// \brief Determine whether the next set of tokens contains a type-id. 
+  ///
+  /// The context parameter states what context we're parsing right
+  /// now, which affects how this routine copes with the token
+  /// following the type-id. If the context is TypeIdInParens, we have
+  /// already parsed the '(' and we will cease lookahead when we hit
+  /// the corresponding ')'. If the context is
+  /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
+  /// before this template argument, and will cease lookahead when we
+  /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
+  /// and false for an expression.  If during the disambiguation
+  /// process a parsing error is encountered, the function returns
+  /// true to let the declaration parsing code handle it.
+  ///
+  /// type-id:
+  ///   type-specifier-seq abstract-declarator[opt]
+  ///
+bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context) {
 
   // C++ 8.2p2:
   // The ambiguity arising from the similarity between a function-style cast and
@@ -318,7 +326,14 @@
   if (TPR == TPResult::Ambiguous()) {
     // We are supposed to be inside parens, so if after the abstract declarator
     // we encounter a ')' this is a type-id, otherwise it's an expression.
-    if (Tok.is(tok::r_paren))
+    if (Context == TypeIdInParens && Tok.is(tok::r_paren))
+      TPR = TPResult::True();
+    // We are supposed to be inside a template argument, so if after
+    // the abstract declarator we encounter a '>', '>>' (in C++0x), or
+    // ',', this is a type-id. Otherwise, it's an expression.
+    else if (Context == TypeIdAsTemplateArgument &&
+             (Tok.is(tok::greater) || Tok.is(tok::comma) ||
+              (getLang().CPlusPlus0x && Tok.is(tok::greatergreater))))
       TPR = TPResult::True();
     else
       TPR = TPResult::False();