]> granicus.if.org Git - clang/commitdiff
Support for 'template' as a disambiguator (PR7030)
authorDouglas Gregor <dgregor@apple.com>
Wed, 5 May 2010 05:58:24 +0000 (05:58 +0000)
committerDouglas Gregor <dgregor@apple.com>
Wed, 5 May 2010 05:58:24 +0000 (05:58 +0000)
    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!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103081 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 42a41d6d30286bfdaa39624beba3995658d31feb..0180419e0429ff7e9f6851c9f356ebfa8ce08565 100644 (file)
@@ -1403,7 +1403,8 @@ private:
                                     bool EnteringContext,
                                     TypeTy *ObjectType,
                                     UnqualifiedId &Id,
-                                    bool AssumeTemplateId = false);
+                                    bool AssumeTemplateId,
+                                    SourceLocation TemplateKWLoc);
   bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
                                   TypeTy *ObjectType,
                                   UnqualifiedId &Result);
index 146762b83ad55f1b11627bb8b59837e5e8f938fd..9eb95062394ac0b819d3ba212109f0947366744d 100644 (file)
@@ -576,7 +576,8 @@ Parser::ParseCXXPseudoDestructor(ExprArg Base, SourceLocation OpLoc,
   // 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 Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
                                           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 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
   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 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
     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 @@ bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
   // 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 Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
                                 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 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
     }
 
     // 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 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
     //     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 @@ bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
     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.
index 694b21c8393f5251311199fceb8fc949a5d9edd5..050bbbd6836d33b22c20a72040d4c37197401f1b 100644 (file)
@@ -1704,7 +1704,8 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
       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 @@ Sema::ActOnDependentTemplateName(SourceLocation TemplateKWLoc,
   Diag(Name.getSourceRange().getBegin(), 
        diag::err_template_kw_refers_to_non_template)
     << GetNameFromUnqualifiedId(Name)
-    << Name.getSourceRange();
+    << Name.getSourceRange()
+    << TemplateKWLoc;
   return TemplateTy();
 }
 
index b3f41be7bfadcecbe80e989f9ea0166bcbdbd682..de8d7f6c91a4aa52e735b8ab9a1c6f44c403e262 100644 (file)
@@ -44,3 +44,41 @@ struct X {
 };
 
 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'}}
+  }
+};