[cfe-commits] r86841 - in /cfe/trunk: lib/AST/TemplateBase.cpp lib/Parse/ParseExprCXX.cpp test/SemaTemplate/default-arguments.cpp test/SemaTemplate/nested-name-spec-template.cpp

Douglas Gregor dgregor at apple.com
Wed Nov 11 08:39:34 PST 2009


Author: dgregor
Date: Wed Nov 11 10:39:34 2009
New Revision: 86841

URL: http://llvm.org/viewvc/llvm-project?rev=86841&view=rev
Log:
Fix speculative parsing of dependent template names in
nested-name-specifiers so that they don't gobble the template name (or
operator-function-id) unless there is also a
template-argument-list. For example, given

  T::template apply

we would previously consume both "template" and "apply" as part of
parsing the nested-name-specifier, then error when we see that there
is no "<" starting a template argument list. Now, we parse such
constructs tentatively, and back off if the "<" is not present. This
allows us to parse dependent template names as one would use them for,
e.g., template template parameters:

  template<typename T, template<class> class X = T::template apply>
    struct MetaSomething;

Also, test default arguments for template template parameters.


Modified:
    cfe/trunk/lib/AST/TemplateBase.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/test/SemaTemplate/default-arguments.cpp
    cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp

Modified: cfe/trunk/lib/AST/TemplateBase.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/TemplateBase.cpp?rev=86841&r1=86840&r2=86841&view=diff

==============================================================================
--- cfe/trunk/lib/AST/TemplateBase.cpp (original)
+++ cfe/trunk/lib/AST/TemplateBase.cpp Wed Nov 11 10:39:34 2009
@@ -59,7 +59,8 @@
     break;
 
   case Template:
-    ID.AddPointer(getAsTemplate().getAsVoidPointer());
+    ID.AddPointer(Context.getCanonicalTemplateName(getAsTemplate())
+                    .getAsVoidPointer());
     break;
       
   case Integral:

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=86841&r1=86840&r2=86841&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed Nov 11 10:39:34 2009
@@ -109,52 +109,43 @@
       if (!HasScopeSpecifier && !ObjectType)
         break;
 
+      TentativeParsingAction TPA(*this);
       SourceLocation TemplateKWLoc = ConsumeToken();
       
       UnqualifiedId TemplateName;
       if (Tok.is(tok::identifier)) {
-        TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
-        
-        // If the next token is not '<', we may have a stray 'template' keyword.
-        // Complain and suggest removing the template keyword, but otherwise
-        // allow parsing to continue.
-        if (NextToken().isNot(tok::less)) {
-          Diag(NextToken().getLocation(),
-               diag::err_less_after_template_name_in_nested_name_spec)
-            << Tok.getIdentifierInfo()->getName()
-            << CodeModificationHint::CreateRemoval(SourceRange(TemplateKWLoc));
-          break;
-        }
-        
         // Consume the identifier.
+        TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
         ConsumeToken();
       } else if (Tok.is(tok::kw_operator)) {
         if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, 
-                                       TemplateName))
+                                       TemplateName)) {
+          TPA.Commit();
           break;
+        }
         
         if (TemplateName.getKind() != UnqualifiedId::IK_OperatorFunctionId) {
           Diag(TemplateName.getSourceRange().getBegin(),
                diag::err_id_after_template_in_nested_name_spec)
             << TemplateName.getSourceRange();
-          break;
-        } else if (Tok.isNot(tok::less)) {
-          std::string OperatorName = "operator ";
-          OperatorName += getOperatorSpelling(
-                                      TemplateName.OperatorFunctionId.Operator);
-          Diag(Tok.getLocation(),
-               diag::err_less_after_template_name_in_nested_name_spec)
-            << OperatorName
-            << TemplateName.getSourceRange();
+          TPA.Commit();
           break;
         }
       } else {
-        Diag(Tok.getLocation(),
-             diag::err_id_after_template_in_nested_name_spec)
-          << SourceRange(TemplateKWLoc);
+        TPA.Revert();
         break;
       }
 
+      // If the next token is not '<', we have a qualified-id that refers
+      // to a template name, such as T::template apply, but is not a 
+      // template-id.
+      if (Tok.isNot(tok::less)) {
+        TPA.Revert();
+        break;
+      }        
+      
+      // Commit to parsing the template-id.
+      TPA.Commit();
       TemplateTy Template
         = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
                                              ObjectType);

Modified: cfe/trunk/test/SemaTemplate/default-arguments.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/default-arguments.cpp?rev=86841&r1=86840&r2=86841&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/default-arguments.cpp (original)
+++ cfe/trunk/test/SemaTemplate/default-arguments.cpp Wed Nov 11 10:39:34 2009
@@ -1,5 +1,4 @@
 // RUN: clang-cc -fsyntax-only -verify %s
-
 template<typename T, int N = 2> struct X; // expected-note{{template is declared here}}
 
 X<int, 1> *x1;
@@ -80,16 +79,31 @@
 X2<int>::Inner3<float>::VeryInner<> vi;
 X2<char>::Inner3<int>::NonType2<> x2_deep_nontype;
 
-
 template<typename T, typename U>
 struct is_same { static const bool value = false; };
 
 template<typename T>
 struct is_same<T, T> { static const bool value = true; };
 
-static int array1[is_same<__typeof__(vi), 
+int array1[is_same<__typeof__(vi), 
                X2<int>::Inner3<float>::VeryInner<int, float> >::value? 1 : -1];
 
-static int array2[is_same<__typeof(x2_deep_nontype),
-                     X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int), 
+int array2[is_same<__typeof(x2_deep_nontype),
+                   X2<char>::Inner3<int>::NonType2<sizeof(char), sizeof(int), 
                                     sizeof(char)+sizeof(int)> >::value? 1 : -1];
+
+// Template template parameter defaults
+template<template<typename T> class X = X2> struct X3 { };
+int array3[is_same<X3<>, X3<X2> >::value? 1 : -1];
+
+struct add_pointer {
+  template<typename T>
+  struct apply {
+    typedef T* type;
+  };
+};
+
+template<typename T, template<typename> class X = T::template apply>
+  struct X4;
+int array4[is_same<X4<add_pointer>, 
+                   X4<add_pointer, add_pointer::apply> >::value? 1 : -1];

Modified: cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp?rev=86841&r1=86840&r2=86841&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/nested-name-spec-template.cpp Wed Nov 11 10:39:34 2009
@@ -28,11 +28,8 @@
 ::N::M::Promote<int>::type *ret_intptr6(int* ip) { return ip; }
 
 
-N::M::template; // expected-error{{expected template name after 'template' keyword in nested name specifier}} \
-               // expected-error{{expected unqualified-id}}
-
-N::M::template Promote; // expected-error{{expected '<' after 'template Promote' in nested name specifier}} \
-// expected-error{{C++ requires a type specifier for all declarations}}
+N::M::template; // expected-error{{expected unqualified-id}}
+N::M::template Promote; // expected-error{{expected unqualified-id}}
 
 namespace N {
   template<typename T> struct A;
@@ -49,13 +46,9 @@
   int foo;
 };
 
-#if 0
-// FIXME: the following crashes the parser, because Sema has no way to
-// communicate that the "dependent" template-name N::template B doesn't
-// actually refer to a template.
 template<typename T>
 struct TestA {
-  typedef typename N::template B<T>::type type; // xpected-error{{'B' following the 'template' keyword does not refer to a template}}
-  // FIXME: should show what B *does* refer to.
+  typedef typename N::template B<T>::type type; // expected-error{{'B' following the 'template' keyword does not refer to a template}} \
+                                                // expected-error{{identifier or template-id}} \
+                                                // expected-error{{expected member name}}
 };
-#endif





More information about the cfe-commits mailing list