[cfe-commits] r103081 - in /cfe/trunk: include/clang/Parse/Parser.h lib/Parse/ParseExprCXX.cpp lib/Sema/SemaTemplate.cpp test/SemaTemplate/template-id-expr.cpp

Douglas Gregor dgregor at apple.com
Tue May 4 22:58:24 PDT 2010


Author: dgregor
Date: Wed May  5 00:58:24 2010
New Revision: 103081

URL: http://llvm.org/viewvc/llvm-project?rev=103081&view=rev
Log:
    Support for 'template' as a disambiguator (PR7030)

    ParseOptionalCXXScopeSpecifier() only annotates the subset of
    template-ids which are not subject to lexical ambiguity. Add support
    for the more general case in ParseUnqualifiedId() to handle cases
    such as A::template B().

    Also improve some diagnostic locations.

Fixes PR7030, from Alp Toker!

Modified:
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/test/SemaTemplate/template-id-expr.cpp

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=103081&r1=103080&r2=103081&view=diff
==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Wed May  5 00:58:24 2010
@@ -1403,7 +1403,8 @@
                                     bool EnteringContext,
                                     TypeTy *ObjectType,
                                     UnqualifiedId &Id,
-                                    bool AssumeTemplateId = false);
+                                    bool AssumeTemplateId,
+                                    SourceLocation TemplateKWLoc);
   bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
                                   TypeTy *ObjectType,
                                   UnqualifiedId &Result);

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=103081&r1=103080&r2=103081&view=diff
==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Wed May  5 00:58:24 2010
@@ -576,7 +576,8 @@
   // it as such.
   if (Tok.is(tok::less) &&
       ParseUnqualifiedIdTemplateId(SS, Name, NameLoc, false, ObjectType,
-                                   SecondTypeName, /*AssumeTemplateName=*/true))
+                                   SecondTypeName, /*AssumeTemplateName=*/true,
+                                   /*TemplateKWLoc*/SourceLocation()))
     return ExprError();
 
   return Actions.ActOnPseudoDestructorExpr(CurScope, move(Base), OpLoc, OpKind,
@@ -952,8 +953,10 @@
                                           bool EnteringContext,
                                           TypeTy *ObjectType,
                                           UnqualifiedId &Id,
-                                          bool AssumeTemplateId) {
-  assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
+                                          bool AssumeTemplateId,
+                                          SourceLocation TemplateKWLoc) {
+  assert((AssumeTemplateId || Tok.is(tok::less)) &&
+         "Expected '<' to finish parsing a template-id");
   
   TemplateTy Template;
   TemplateNameKind TNK = TNK_Non_template;
@@ -962,7 +965,7 @@
   case UnqualifiedId::IK_OperatorFunctionId:
   case UnqualifiedId::IK_LiteralOperatorId:
     if (AssumeTemplateId) {
-      Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, 
+      Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, 
                                                     Id, ObjectType,
                                                     EnteringContext);
       TNK = TNK_Dependent_template_name;
@@ -985,7 +988,7 @@
     UnqualifiedId TemplateName;
     TemplateName.setIdentifier(Name, NameLoc);
     if (ObjectType) {
-      Template = Actions.ActOnDependentTemplateName(SourceLocation(), SS, 
+      Template = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, 
                                                     TemplateName, ObjectType,
                                                     EnteringContext);
       TNK = TNK_Dependent_template_name;
@@ -1014,7 +1017,8 @@
   // Parse the enclosed template argument list.
   SourceLocation LAngleLoc, RAngleLoc;
   TemplateArgList TemplateArgs;
-  if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
+  if (Tok.is(tok::less) &&
+      ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
                                        &SS, true, LAngleLoc,
                                        TemplateArgs,
                                        RAngleLoc))
@@ -1293,6 +1297,17 @@
                                 bool AllowConstructorName,
                                 TypeTy *ObjectType,
                                 UnqualifiedId &Result) {
+
+  // Handle 'A::template B'. This is for template-ids which have not
+  // already been annotated by ParseOptionalCXXScopeSpecifier().
+  bool TemplateSpecified = false;
+  SourceLocation TemplateKWLoc;
+  if (getLang().CPlusPlus && Tok.is(tok::kw_template) &&
+      (ObjectType || SS.isSet())) {
+    TemplateSpecified = true;
+    TemplateKWLoc = ConsumeToken();
+  }
+
   // unqualified-id:
   //   identifier
   //   template-id (when it hasn't already been annotated)
@@ -1320,9 +1335,10 @@
     }
 
     // If the next token is a '<', we may have a template.
-    if (Tok.is(tok::less))
+    if (TemplateSpecified || Tok.is(tok::less))
       return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, 
-                                          ObjectType, Result);
+                                          ObjectType, Result,
+                                          TemplateSpecified, TemplateKWLoc);
     
     return false;
   }
@@ -1383,10 +1399,11 @@
     //     operator-function-id < template-argument-list[opt] >
     if ((Result.getKind() == UnqualifiedId::IK_OperatorFunctionId ||
          Result.getKind() == UnqualifiedId::IK_LiteralOperatorId) &&
-        Tok.is(tok::less))
+        (TemplateSpecified || Tok.is(tok::less)))
       return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), 
                                           EnteringContext, ObjectType, 
-                                          Result);
+                                          Result,
+                                          TemplateSpecified, TemplateKWLoc);
     
     return false;
   }
@@ -1411,10 +1428,11 @@
     IdentifierInfo *ClassName = Tok.getIdentifierInfo();
     SourceLocation ClassNameLoc = ConsumeToken();
     
-    if (Tok.is(tok::less)) {
+    if (TemplateSpecified || Tok.is(tok::less)) {
       Result.setDestructorName(TildeLoc, 0, ClassNameLoc);
       return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
-                                          EnteringContext, ObjectType, Result);
+                                          EnteringContext, ObjectType, Result,
+                                          TemplateSpecified, TemplateKWLoc);
     }
     
     // Note that this is a destructor name.

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=103081&r1=103080&r2=103081&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Wed May  5 00:58:24 2010
@@ -1704,7 +1704,8 @@
       Diag(Name.getSourceRange().getBegin(), 
            diag::err_template_kw_refers_to_non_template)
         << GetNameFromUnqualifiedId(Name)
-        << Name.getSourceRange();
+        << Name.getSourceRange()
+        << TemplateKWLoc;
       return TemplateTy();
     } else {
       // We found something; return it.
@@ -1734,7 +1735,8 @@
   Diag(Name.getSourceRange().getBegin(), 
        diag::err_template_kw_refers_to_non_template)
     << GetNameFromUnqualifiedId(Name)
-    << Name.getSourceRange();
+    << Name.getSourceRange()
+    << TemplateKWLoc;
   return TemplateTy();
 }
 

Modified: cfe/trunk/test/SemaTemplate/template-id-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/template-id-expr.cpp?rev=103081&r1=103080&r2=103081&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/template-id-expr.cpp (original)
+++ cfe/trunk/test/SemaTemplate/template-id-expr.cpp Wed May  5 00:58:24 2010
@@ -44,3 +44,41 @@
 };
 
 template struct X<3>;
+
+// 'template' as a disambiguator.
+// PR7030
+struct Y0 {
+  template<typename U>
+  void f1(U);
+
+  template<typename U>
+  static void f2(U);
+
+  void f3(int);
+
+  static int f4(int);
+  template<typename U>
+  static void f4(U);
+
+  template<typename U>
+  void f() {
+    Y0::template f1<U>(0);
+    Y0::template f1(0);
+    this->template f1(0);
+
+    Y0::template f2<U>(0);
+    Y0::template f2(0);
+
+    Y0::template f3(0); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+    Y0::template f3(); // expected-error {{'f3' following the 'template' keyword does not refer to a template}}
+
+    int x;
+    x = Y0::f4(0);
+    x = Y0::f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+    x = Y0::template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+
+    x = this->f4(0);
+    x = this->f4<int>(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+    x = this->template f4(0); // expected-error {{assigning to 'int' from incompatible type 'void'}}
+  }
+};





More information about the cfe-commits mailing list