r340074 - Improve diagnostic for missing comma in template parameter list.

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Fri Aug 17 12:43:40 PDT 2018


Author: rsmith
Date: Fri Aug 17 12:43:40 2018
New Revision: 340074

URL: http://llvm.org/viewvc/llvm-project?rev=340074&view=rev
Log:
Improve diagnostic for missing comma in template parameter list.

Given 'typename T typename U', we would correctly diagnose the missing
comma, but incorrectly disambiguate the first parameter as being a
non-type parameter and complain that the 'T' is not a qualified-id.

See also gcc.gnu.org/PR86998.

Modified:
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/test/CXX/temp/temp.param/p2.cpp

Modified: cfe/trunk/lib/Parse/ParseTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseTemplate.cpp?rev=340074&r1=340073&r2=340074&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Fri Aug 17 12:43:40 2018
@@ -425,7 +425,9 @@ bool Parser::isStartOfTemplateTypeParame
     }
   }
 
-  if (Tok.isNot(tok::kw_typename))
+  // 'typedef' is a reasonably-common typo/thinko for 'typename', and is
+  // ill-formed otherwise.
+  if (Tok.isNot(tok::kw_typename) && Tok.isNot(tok::kw_typedef))
     return false;
 
   // C++ [temp.param]p2:
@@ -448,6 +450,13 @@ bool Parser::isStartOfTemplateTypeParame
   case tok::ellipsis:
     return true;
 
+  case tok::kw_typename:
+  case tok::kw_typedef:
+  case tok::kw_class:
+    // These indicate that a comma was missed after a type parameter, not that
+    // we have found a non-type parameter.
+    return true;
+
   default:
     return false;
   }
@@ -469,26 +478,25 @@ bool Parser::isStartOfTemplateTypeParame
 ///         'template' '<' template-parameter-list '>' 'class' identifier[opt]
 ///               = id-expression
 NamedDecl *Parser::ParseTemplateParameter(unsigned Depth, unsigned Position) {
-  if (isStartOfTemplateTypeParameter())
-    return ParseTypeParameter(Depth, Position);
-
-  if (Tok.is(tok::kw_template))
-    return ParseTemplateTemplateParameter(Depth, Position);
+  if (isStartOfTemplateTypeParameter()) {
+    // Is there just a typo in the input code? ('typedef' instead of 'typename')
+    if (Tok.is(tok::kw_typedef)) {
+      Diag(Tok.getLocation(), diag::err_expected_template_parameter);
+
+      Diag(Tok.getLocation(), diag::note_meant_to_use_typename)
+          << FixItHint::CreateReplacement(CharSourceRange::getCharRange(
+                                              Tok.getLocation(), Tok.getEndLoc()),
+                                          "typename");
 
-  // Is there just a typo in the input code? ('typedef' instead of 'typename')
-  if (Tok.is(tok::kw_typedef)) {
-    Diag(Tok.getLocation(), diag::err_expected_template_parameter);
-
-    Diag(Tok.getLocation(), diag::note_meant_to_use_typename)
-        << FixItHint::CreateReplacement(CharSourceRange::getCharRange(
-                                            Tok.getLocation(), Tok.getEndLoc()),
-                                        "typename");
-
-    Tok.setKind(tok::kw_typename);
+      Tok.setKind(tok::kw_typename);
+    }
 
     return ParseTypeParameter(Depth, Position);
   }
 
+  if (Tok.is(tok::kw_template))
+    return ParseTemplateTemplateParameter(Depth, Position);
+
   // If it's none of the above, then it must be a parameter declaration.
   // NOTE: This will pick up errors in the closure of the template parameter
   // list (e.g., template < ; Check here to implement >> style closures.

Modified: cfe/trunk/test/CXX/temp/temp.param/p2.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.param/p2.cpp?rev=340074&r1=340073&r2=340074&view=diff
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.param/p2.cpp (original)
+++ cfe/trunk/test/CXX/temp/temp.param/p2.cpp Fri Aug 17 12:43:40 2018
@@ -8,14 +8,17 @@
 template<class T> struct X;
 template<typename T> struct X;
 
-// typename followed by aqualified-id denotes the type in a non-type
+// typename followed by a qualified-id denotes the type in a non-type
 // parameter-declaration.
 template<typename T, typename T::type Value> struct Y0;
 template<typename T, typename X<T>::type Value> struct Y1;
+template<typename T typename U> struct Y2; // expected-error{{expected ',' or '>'}}
+template<typename T U> struct Y3; // expected-error{{expected a qualified name after 'typename'}} expected-error{{expected ',' or '>'}}
+template<typedef T typename U> struct Y4; // expected-error{{expected template parameter}} expected-note {{did you mean to use 'typename'?}} expected-error{{expected ',' or '>'}}
 
 // A storage class shall not be specified in a template-parameter declaration.
 template<static int Value> struct Z; //expected-error{{invalid declaration specifier}}
-template<typedef int Value> struct Z0; //expected-error{{expected template parameter}} expected-error{{expected identifier}} expected-error{{extraneous 'template<>' in declaration of struct 'Z0'}} expected-note{{did you mean to use 'typename'?}}
+template<typedef int Value> struct Z0; //expected-error{{invalid declaration specifier}}
 template<extern inline int Value> struct Z1; //expected-error2{{invalid declaration specifier}}
 template<virtual int Value> struct Z2; //expected-error{{invalid declaration specifier}}
 template<explicit int Value> struct Z3; //expected-error{{invalid declaration specifier}}
@@ -43,6 +46,6 @@ template<auto> struct Z13; // OK
 // Make sure that we properly disambiguate non-type template parameters that
 // start with 'class'.
 class X1 { };
-template<class X1 *xptr> struct Y2 { };
+template<class X1 *xptr> struct X2 { };
 
 // FIXME: add the example from p2




More information about the cfe-commits mailing list