[cfe-commits] r85989 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/TemplateName.h include/clang/Basic/OperatorKinds.h include/clang/Parse/Parser.h lib/AST/ASTContext.cpp lib/AST/TemplateName.cpp lib/Basic/IdentifierTable.cpp lib/Parse/ParseExprCXX.cpp lib/Parse/ParseTemplate.cpp lib/Parse/Parser.cpp lib/Sema/SemaExpr.cpp lib/Sema/SemaTemplate.cpp lib/Sema/TreeTransform.h test/SemaCXX/invalid-template-specifier.cpp test/SemaTemplate/operator-function-id-template.cpp

Douglas Gregor dgregor at apple.com
Tue Nov 3 16:56:37 PST 2009


Author: dgregor
Date: Tue Nov  3 18:56:37 2009
New Revision: 85989

URL: http://llvm.org/viewvc/llvm-project?rev=85989&view=rev
Log:
Implement support for parsing dependent template-ids that refer to
overloaded operators, e.g.,

  p->template operator+<T>()



Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/TemplateName.h
    cfe/trunk/include/clang/Basic/OperatorKinds.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/TemplateName.cpp
    cfe/trunk/lib/Basic/IdentifierTable.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Parse/ParseTemplate.cpp
    cfe/trunk/lib/Parse/Parser.cpp
    cfe/trunk/lib/Sema/SemaExpr.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/TreeTransform.h
    cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp
    cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Tue Nov  3 18:56:37 2009
@@ -16,6 +16,7 @@
 
 #include "clang/Basic/IdentifierTable.h"
 #include "clang/Basic/LangOptions.h"
+#include "clang/Basic/OperatorKinds.h"
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/NestedNameSpecifier.h"
@@ -739,6 +740,8 @@
 
   TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
                                         const IdentifierInfo *Name);
+  TemplateName getDependentTemplateName(NestedNameSpecifier *NNS,
+                                        OverloadedOperatorKind Operator);
 
   enum GetBuiltinTypeError {
     GE_None,              //< No error

Modified: cfe/trunk/include/clang/AST/TemplateName.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/TemplateName.h?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/TemplateName.h (original)
+++ cfe/trunk/include/clang/AST/TemplateName.h Tue Nov  3 18:56:37 2009
@@ -16,6 +16,7 @@
 
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/ADT/PointerUnion.h"
+#include "clang/Basic/OperatorKinds.h"
 
 namespace llvm {
   class raw_ostream;
@@ -224,10 +225,24 @@
 class DependentTemplateName : public llvm::FoldingSetNode {
   /// \brief The nested name specifier that qualifies the template
   /// name.
-  NestedNameSpecifier *Qualifier;
+  ///
+  /// The bit stored in this qualifier describes whether the \c Name field
+  /// is interpreted as an IdentifierInfo pointer (when clear) or as an
+  /// overloaded operator kind (when set).
+  llvm::PointerIntPair<NestedNameSpecifier *, 1, bool> Qualifier;
 
   /// \brief The dependent template name.
-  const IdentifierInfo *Name;
+  union {
+    /// \brief The identifier template name.
+    ///
+    /// Only valid when the bit on \c Qualifier is clear.
+    const IdentifierInfo *Identifier;
+    
+    /// \brief The overloaded operator name.
+    ///
+    /// Only valid when the bit on \c Qualifier is set.
+    OverloadedOperatorKind Operator;
+  };
 
   /// \brief The canonical template name to which this dependent
   /// template name refers.
@@ -240,30 +255,70 @@
   friend class ASTContext;
 
   DependentTemplateName(NestedNameSpecifier *Qualifier,
-                        const IdentifierInfo *Name)
-    : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(this) { }
+                        const IdentifierInfo *Identifier)
+    : Qualifier(Qualifier, false), Identifier(Identifier), 
+      CanonicalTemplateName(this) { }
 
   DependentTemplateName(NestedNameSpecifier *Qualifier,
-                        const IdentifierInfo *Name,
+                        const IdentifierInfo *Identifier,
                         TemplateName Canon)
-    : Qualifier(Qualifier), Name(Name), CanonicalTemplateName(Canon) { }
+    : Qualifier(Qualifier, false), Identifier(Identifier), 
+      CanonicalTemplateName(Canon) { }
 
+  DependentTemplateName(NestedNameSpecifier *Qualifier,
+                        OverloadedOperatorKind Operator)
+  : Qualifier(Qualifier, true), Operator(Operator), 
+    CanonicalTemplateName(this) { }
+  
+  DependentTemplateName(NestedNameSpecifier *Qualifier,
+                        OverloadedOperatorKind Operator,
+                        TemplateName Canon)
+  : Qualifier(Qualifier, true), Operator(Operator), 
+    CanonicalTemplateName(Canon) { }
+  
 public:
   /// \brief Return the nested name specifier that qualifies this name.
-  NestedNameSpecifier *getQualifier() const { return Qualifier; }
+  NestedNameSpecifier *getQualifier() const { return Qualifier.getPointer(); }
 
-  /// \brief Return the name to which this dependent template name
-  /// refers.
-  const IdentifierInfo *getName() const { return Name; }
+  /// \brief Determine whether this template name refers to an identifier.
+  bool isIdentifier() const { return !Qualifier.getInt(); }
 
+  /// \brief Returns the identifier to which this template name refers.
+  const IdentifierInfo *getIdentifier() const { 
+    assert(isIdentifier() && "Template name isn't an identifier?");
+    return Identifier;
+  }
+  
+  /// \brief Determine whether this template name refers to an overloaded
+  /// operator.
+  bool isOverloadedOperator() const { return Qualifier.getInt(); }
+  
+  /// \brief Return the overloaded operator to which this template name refers.
+  OverloadedOperatorKind getOperator() const { 
+    assert(isOverloadedOperator() &&
+           "Template name isn't an overloaded operator?");
+    return Operator; 
+  }
+  
   void Profile(llvm::FoldingSetNodeID &ID) {
-    Profile(ID, getQualifier(), getName());
+    if (isIdentifier())
+      Profile(ID, getQualifier(), getIdentifier());
+    else
+      Profile(ID, getQualifier(), getOperator());
+  }
+
+  static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
+                      const IdentifierInfo *Identifier) {
+    ID.AddPointer(NNS);
+    ID.AddBoolean(false);
+    ID.AddPointer(Identifier);
   }
 
   static void Profile(llvm::FoldingSetNodeID &ID, NestedNameSpecifier *NNS,
-                      const IdentifierInfo *Name) {
+                      OverloadedOperatorKind Operator) {
     ID.AddPointer(NNS);
-    ID.AddPointer(Name);
+    ID.AddBoolean(true);
+    ID.AddInteger(Operator);
   }
 };
 

Modified: cfe/trunk/include/clang/Basic/OperatorKinds.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/OperatorKinds.h?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/OperatorKinds.h (original)
+++ cfe/trunk/include/clang/Basic/OperatorKinds.h Tue Nov  3 18:56:37 2009
@@ -26,7 +26,10 @@
   NUM_OVERLOADED_OPERATORS
 };
 
-
+/// \brief Retrieve the spelling of the given overloaded operator, without 
+/// the preceding "operator" keyword.
+const char *getOperatorSpelling(OverloadedOperatorKind Operator);
+  
 } // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Tue Nov  3 18:56:37 2009
@@ -1218,6 +1218,9 @@
                                     bool EnteringContext,
                                     TypeTy *ObjectType,
                                     UnqualifiedId &Id);
+  bool ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+                                  TypeTy *ObjectType,
+                                  UnqualifiedId &Result);
   bool ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
                           bool AllowDestructorName,
                           bool AllowConstructorName,
@@ -1274,6 +1277,7 @@
 
   bool AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
                                const CXXScopeSpec *SS,
+                               UnqualifiedId &TemplateName,
                                SourceLocation TemplateKWLoc = SourceLocation(),
                                bool AllowTypeAnnotation = true);
   void AnnotateTemplateIdTokenAsType(const CXXScopeSpec *SS = 0);

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

==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Tue Nov  3 18:56:37 2009
@@ -3662,6 +3662,36 @@
   return TemplateName(QTN);
 }
 
+/// \brief Retrieve the template name that represents a dependent
+/// template name such as \c MetaFun::template operator+.
+TemplateName 
+ASTContext::getDependentTemplateName(NestedNameSpecifier *NNS,
+                                     OverloadedOperatorKind Operator) {
+  assert((!NNS || NNS->isDependent()) &&
+         "Nested name specifier must be dependent");
+  
+  llvm::FoldingSetNodeID ID;
+  DependentTemplateName::Profile(ID, NNS, Operator);
+  
+  void *InsertPos = 0;
+  DependentTemplateName *QTN =
+  DependentTemplateNames.FindNodeOrInsertPos(ID, InsertPos);
+  
+  if (QTN)
+    return TemplateName(QTN);
+  
+  NestedNameSpecifier *CanonNNS = getCanonicalNestedNameSpecifier(NNS);
+  if (CanonNNS == NNS) {
+    QTN = new (*this,4) DependentTemplateName(NNS, Operator);
+  } else {
+    TemplateName Canon = getDependentTemplateName(CanonNNS, Operator);
+    QTN = new (*this,4) DependentTemplateName(NNS, Operator, Canon);
+  }
+  
+  DependentTemplateNames.InsertNode(QTN, InsertPos);
+  return TemplateName(QTN);
+}
+
 /// getFromTargetType - Given one of the integer types provided by
 /// TargetInfo, produce the corresponding type. The unsigned @p Type
 /// is actually a value of type @c TargetInfo::IntType.

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

==============================================================================
--- cfe/trunk/lib/AST/TemplateName.cpp (original)
+++ cfe/trunk/lib/AST/TemplateName.cpp Tue Nov  3 18:56:37 2009
@@ -56,7 +56,7 @@
 TemplateName::print(llvm::raw_ostream &OS, const PrintingPolicy &Policy,
                     bool SuppressNNS) const {
   if (TemplateDecl *Template = Storage.dyn_cast<TemplateDecl *>())
-    OS << Template->getIdentifier()->getName();
+    OS << Template->getNameAsString();
   else if (OverloadedFunctionDecl *Ovl
              = Storage.dyn_cast<OverloadedFunctionDecl *>())
     OS << Ovl->getNameAsString();
@@ -70,8 +70,11 @@
     if (!SuppressNNS && DTN->getQualifier())
       DTN->getQualifier()->print(OS, Policy);
     OS << "template ";
-    // FIXME: Shouldn't we have a more general kind of name?
-    OS << DTN->getName()->getName();
+    
+    if (DTN->isIdentifier())
+      OS << DTN->getIdentifier()->getName();
+    else
+      OS << "operator " << getOperatorSpelling(DTN->getOperator());
   }
 }
 

Modified: cfe/trunk/lib/Basic/IdentifierTable.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Basic/IdentifierTable.cpp?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/lib/Basic/IdentifierTable.cpp (original)
+++ cfe/trunk/lib/Basic/IdentifierTable.cpp Tue Nov  3 18:56:37 2009
@@ -381,3 +381,17 @@
   delete &getSelectorTableImpl(Impl);
 }
 
+const char *clang::getOperatorSpelling(OverloadedOperatorKind Operator) {
+  switch (Operator) {
+  case OO_None:
+  case NUM_OVERLOADED_OPERATORS:
+    return 0;
+      
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+  case OO_##Name: return Spelling;
+#include "clang/Basic/OperatorKinds.def"
+  }
+  
+  return 0;
+}
+

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Tue Nov  3 18:56:37 2009
@@ -109,31 +109,58 @@
         break;
 
       SourceLocation TemplateKWLoc = ConsumeToken();
-
-      if (Tok.isNot(tok::identifier)) {
+      
+      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.
+        ConsumeToken();
+      } else if (Tok.is(tok::kw_operator)) {
+        if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, 
+                                       TemplateName))
+          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();
+          break;
+        }
+      } else {
         Diag(Tok.getLocation(),
              diag::err_id_after_template_in_nested_name_spec)
           << SourceRange(TemplateKWLoc);
         break;
       }
 
-      if (NextToken().isNot(tok::less)) {
-        Diag(NextToken().getLocation(),
-             diag::err_less_after_template_name_in_nested_name_spec)
-          << Tok.getIdentifierInfo()->getName()
-          << SourceRange(TemplateKWLoc, Tok.getLocation());
-        break;
-      }
-
-      UnqualifiedId TemplateName;
-      TemplateName.setIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());
       TemplateTy Template
         = Actions.ActOnDependentTemplateName(TemplateKWLoc, SS, TemplateName,
                                              ObjectType);
       if (!Template)
         break;
       if (AnnotateTemplateIdToken(Template, TNK_Dependent_template_name,
-                                  &SS, TemplateKWLoc, false))
+                                  &SS, TemplateName, TemplateKWLoc, false))
         break;
 
       continue;
@@ -233,8 +260,9 @@
         // because some clients (e.g., the parsing of class template
         // specializations) still want to see the original template-id
         // token.
-        if (AnnotateTemplateIdToken(Template, TNK, &SS, SourceLocation(),
-                                    false))
+        ConsumeToken();
+        if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName, 
+                                    SourceLocation(), false))
           break;
         continue;
       }
@@ -859,22 +887,17 @@
   return false;
 }
 
-/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the
-/// name of an entity.
+/// \brief Parse an operator-function-id or conversion-function-id as part
+/// of a C++ unqualified-id.
 ///
-/// \code
-///       unqualified-id: [C++ expr.prim.general]
-///         identifier
-///         operator-function-id
-///         conversion-function-id
-/// [C++0x] literal-operator-id [TODO]
-///         ~ class-name
-///         template-id
+/// This routine is responsible only for parsing the operator-function-id or
+/// conversion-function-id; it does not handle template arguments in any way.
 ///
+/// \code
 ///       operator-function-id: [C++ 13.5]
 ///         'operator' operator
 ///
-/// operator: one of
+///       operator: one of
 ///            new   delete  new[]   delete[]
 ///            +     -    *  /    %  ^    &   |   ~
 ///            !     =    <  >    += -=   *=  /=  %=
@@ -898,6 +921,159 @@
 /// \param EnteringContext whether we are entering the scope of the 
 /// nested-name-specifier.
 ///
+/// \param ObjectType if this unqualified-id occurs within a member access
+/// expression, the type of the base object whose member is being accessed.
+///
+/// \param Result on a successful parse, contains the parsed unqualified-id.
+///
+/// \returns true if parsing fails, false otherwise.
+bool Parser::ParseUnqualifiedIdOperator(CXXScopeSpec &SS, bool EnteringContext,
+                                        TypeTy *ObjectType,
+                                        UnqualifiedId &Result) {
+  assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
+  
+  // Consume the 'operator' keyword.
+  SourceLocation KeywordLoc = ConsumeToken();
+  
+  // Determine what kind of operator name we have.
+  unsigned SymbolIdx = 0;
+  SourceLocation SymbolLocations[3];
+  OverloadedOperatorKind Op = OO_None;
+  switch (Tok.getKind()) {
+    case tok::kw_new:
+    case tok::kw_delete: {
+      bool isNew = Tok.getKind() == tok::kw_new;
+      // Consume the 'new' or 'delete'.
+      SymbolLocations[SymbolIdx++] = ConsumeToken();
+      if (Tok.is(tok::l_square)) {
+        // Consume the '['.
+        SourceLocation LBracketLoc = ConsumeBracket();
+        // Consume the ']'.
+        SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+                                                         LBracketLoc);
+        if (RBracketLoc.isInvalid())
+          return true;
+        
+        SymbolLocations[SymbolIdx++] = LBracketLoc;
+        SymbolLocations[SymbolIdx++] = RBracketLoc;
+        Op = isNew? OO_Array_New : OO_Array_Delete;
+      } else {
+        Op = isNew? OO_New : OO_Delete;
+      }
+      break;
+    }
+      
+#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
+    case tok::Token:                                                     \
+      SymbolLocations[SymbolIdx++] = ConsumeToken();                     \
+      Op = OO_##Name;                                                    \
+      break;
+#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
+#include "clang/Basic/OperatorKinds.def"
+      
+    case tok::l_paren: {
+      // Consume the '('.
+      SourceLocation LParenLoc = ConsumeParen();
+      // Consume the ')'.
+      SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
+                                                     LParenLoc);
+      if (RParenLoc.isInvalid())
+        return true;
+      
+      SymbolLocations[SymbolIdx++] = LParenLoc;
+      SymbolLocations[SymbolIdx++] = RParenLoc;
+      Op = OO_Call;
+      break;
+    }
+      
+    case tok::l_square: {
+      // Consume the '['.
+      SourceLocation LBracketLoc = ConsumeBracket();
+      // Consume the ']'.
+      SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
+                                                       LBracketLoc);
+      if (RBracketLoc.isInvalid())
+        return true;
+      
+      SymbolLocations[SymbolIdx++] = LBracketLoc;
+      SymbolLocations[SymbolIdx++] = RBracketLoc;
+      Op = OO_Subscript;
+      break;
+    }
+      
+    case tok::code_completion: {
+      // Code completion for the operator name.
+      Actions.CodeCompleteOperatorName(CurScope);
+      
+      // Consume the operator token.
+      ConsumeToken();
+      
+      // Don't try to parse any further.
+      return true;
+    }
+      
+    default:
+      break;
+  }
+  
+  if (Op != OO_None) {
+    // We have parsed an operator-function-id.
+    Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
+    return false;
+  }
+  
+  // Parse a conversion-function-id.
+  //
+  //   conversion-function-id: [C++ 12.3.2]
+  //     operator conversion-type-id
+  //
+  //   conversion-type-id:
+  //     type-specifier-seq conversion-declarator[opt]
+  //
+  //   conversion-declarator:
+  //     ptr-operator conversion-declarator[opt]
+  
+  // Parse the type-specifier-seq.
+  DeclSpec DS;
+  if (ParseCXXTypeSpecifierSeq(DS))
+    return true;
+  
+  // Parse the conversion-declarator, which is merely a sequence of
+  // ptr-operators.
+  Declarator D(DS, Declarator::TypeNameContext);
+  ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
+  
+  // Finish up the type.
+  Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D);
+  if (Ty.isInvalid())
+    return true;
+  
+  // Note that this is a conversion-function-id.
+  Result.setConversionFunctionId(KeywordLoc, Ty.get(), 
+                                 D.getSourceRange().getEnd());
+  return false;  
+}
+
+/// \brief Parse a C++ unqualified-id (or a C identifier), which describes the
+/// name of an entity.
+///
+/// \code
+///       unqualified-id: [C++ expr.prim.general]
+///         identifier
+///         operator-function-id
+///         conversion-function-id
+/// [C++0x] literal-operator-id [TODO]
+///         ~ class-name
+///         template-id
+///
+/// \endcode
+///
+/// \param The nested-name-specifier that preceded this unqualified-id. If
+/// non-empty, then we are parsing the unqualified-id of a qualified-id.
+///
+/// \param EnteringContext whether we are entering the scope of the 
+/// nested-name-specifier.
+///
 /// \param AllowDestructorName whether we allow parsing of a destructor name.
 ///
 /// \param AllowConstructorName whether we allow parsing a constructor name.
@@ -957,132 +1133,20 @@
   //   operator-function-id
   //   conversion-function-id
   if (Tok.is(tok::kw_operator)) {
-    // Consume the 'operator' keyword.
-    SourceLocation KeywordLoc = ConsumeToken();
-
-    // Determine what kind of operator name we have.
-    unsigned SymbolIdx = 0;
-    SourceLocation SymbolLocations[3];
-    OverloadedOperatorKind Op = OO_None;
-    switch (Tok.getKind()) {
-      case tok::kw_new:
-      case tok::kw_delete: {
-        bool isNew = Tok.getKind() == tok::kw_new;
-        // Consume the 'new' or 'delete'.
-        SymbolLocations[SymbolIdx++] = ConsumeToken();
-        if (Tok.is(tok::l_square)) {
-          // Consume the '['.
-          SourceLocation LBracketLoc = ConsumeBracket();
-          // Consume the ']'.
-          SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
-                                                           LBracketLoc);
-          if (RBracketLoc.isInvalid())
-            return true;
-          
-          SymbolLocations[SymbolIdx++] = LBracketLoc;
-          SymbolLocations[SymbolIdx++] = RBracketLoc;
-          Op = isNew? OO_Array_New : OO_Array_Delete;
-        } else {
-          Op = isNew? OO_New : OO_Delete;
-        }
-        break;
-      }
-        
-  #define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
-      case tok::Token:                                                     \
-        SymbolLocations[SymbolIdx++] = ConsumeToken();                     \
-        Op = OO_##Name;                                                    \
-        break;
-  #define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
-  #include "clang/Basic/OperatorKinds.def"
-        
-      case tok::l_paren: {
-        // Consume the '('.
-        SourceLocation LParenLoc = ConsumeParen();
-        // Consume the ')'.
-        SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren,
-                                                       LParenLoc);
-        if (RParenLoc.isInvalid())
-          return true;
-
-        SymbolLocations[SymbolIdx++] = LParenLoc;
-        SymbolLocations[SymbolIdx++] = RParenLoc;
-        Op = OO_Call;
-        break;
-      }
-        
-      case tok::l_square: {
-        // Consume the '['.
-        SourceLocation LBracketLoc = ConsumeBracket();
-        // Consume the ']'.
-        SourceLocation RBracketLoc = MatchRHSPunctuation(tok::r_square,
-                                                         LBracketLoc);
-        if (RBracketLoc.isInvalid())
-          return true;
-        
-        SymbolLocations[SymbolIdx++] = LBracketLoc;
-        SymbolLocations[SymbolIdx++] = RBracketLoc;
-        Op = OO_Subscript;
-        break;
-      }
-        
-      case tok::code_completion: {
-        // Code completion for the operator name.
-        Actions.CodeCompleteOperatorName(CurScope);
-        
-        // Consume the operator token.
-        ConsumeToken();
-        
-        // Don't try to parse any further.
-        return true;
-      }
-
-      default:
-        break;
-    }
-    
-    if (Op != OO_None) {
-      // We have parsed an operator-function-id.
-      Result.setOperatorFunctionId(KeywordLoc, Op, SymbolLocations);
-      
-      // If the next token is a '<', we may have a template.
-      if (Tok.is(tok::less))
-        return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), 
-                                            EnteringContext, ObjectType, 
-                                            Result);
-
-      return false;
-    }
-    
-    // Parse a conversion-function-id.
-    //
-    //   conversion-function-id: [C++ 12.3.2]
-    //     operator conversion-type-id
-    //
-    //   conversion-type-id:
-    //     type-specifier-seq conversion-declarator[opt]
-    //
-    //   conversion-declarator:
-    //     ptr-operator conversion-declarator[opt]
-    
-    // Parse the type-specifier-seq.
-    DeclSpec DS;
-    if (ParseCXXTypeSpecifierSeq(DS))
+    if (ParseUnqualifiedIdOperator(SS, EnteringContext, ObjectType, Result))
       return true;
     
-    // Parse the conversion-declarator, which is merely a sequence of
-    // ptr-operators.
-    Declarator D(DS, Declarator::TypeNameContext);
-    ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
-    
-    // Finish up the type.
-    Action::TypeResult Ty = Actions.ActOnTypeName(CurScope, D);
-    if (Ty.isInvalid())
-      return true;
+    // If we have an operator-function-id and the next token is a '<', we may
+    // have a
+    // 
+    //   template-id:
+    //     operator-function-id < template-argument-list[opt] >
+    if (Result.getKind() == UnqualifiedId::IK_OperatorFunctionId &&
+        Tok.is(tok::less))
+      return ParseUnqualifiedIdTemplateId(SS, 0, SourceLocation(), 
+                                          EnteringContext, ObjectType, 
+                                          Result);
     
-    // Note that this is a conversion-function-id.
-    Result.setConversionFunctionId(KeywordLoc, Ty.get(), 
-                                   D.getSourceRange().getEnd());
     return false;
   }
   

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

==============================================================================
--- cfe/trunk/lib/Parse/ParseTemplate.cpp (original)
+++ cfe/trunk/lib/Parse/ParseTemplate.cpp Tue Nov  3 18:56:37 2009
@@ -672,22 +672,23 @@
 ///
 bool Parser::AnnotateTemplateIdToken(TemplateTy Template, TemplateNameKind TNK,
                                      const CXXScopeSpec *SS,
+                                     UnqualifiedId &TemplateName,
                                      SourceLocation TemplateKWLoc,
                                      bool AllowTypeAnnotation) {
   assert(getLang().CPlusPlus && "Can only annotate template-ids in C++");
-  assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) &&
+  assert(Template && Tok.is(tok::less) &&
          "Parser isn't at the beginning of a template-id");
 
   // Consume the template-name.
-  IdentifierInfo *Name = Tok.getIdentifierInfo();
-  SourceLocation TemplateNameLoc = ConsumeToken();
+  SourceLocation TemplateNameLoc = TemplateName.getSourceRange().getBegin();
 
   // Parse the enclosed template argument list.
   SourceLocation LAngleLoc, RAngleLoc;
   TemplateArgList TemplateArgs;
   TemplateArgIsTypeList TemplateArgIsType;
   TemplateArgLocationList TemplateArgLocations;
-  bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc,
+  bool Invalid = ParseTemplateIdAfterTemplateName(Template, 
+                                                  TemplateNameLoc,
                                                   SS, false, LAngleLoc,
                                                   TemplateArgs,
                                                   TemplateArgIsType,
@@ -736,7 +737,13 @@
     TemplateIdAnnotation *TemplateId
       = TemplateIdAnnotation::Allocate(TemplateArgs.size());
     TemplateId->TemplateNameLoc = TemplateNameLoc;
-    TemplateId->Name = Name;
+    if (TemplateName.getKind() == UnqualifiedId::IK_Identifier) {
+      TemplateId->Name = TemplateName.Identifier;
+      TemplateId->Operator = OO_None;
+    } else {
+      TemplateId->Name = 0;
+      TemplateId->Operator = TemplateName.OperatorFunctionId.Operator;
+    }
     TemplateId->Template = Template.getAs<void*>();
     TemplateId->Kind = TNK;
     TemplateId->LAngleLoc = LAngleLoc;

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

==============================================================================
--- cfe/trunk/lib/Parse/Parser.cpp (original)
+++ cfe/trunk/lib/Parse/Parser.cpp Tue Nov  3 18:56:37 2009
@@ -940,13 +940,16 @@
       if (TemplateNameKind TNK
             = Actions.isTemplateName(CurScope, SS, TemplateName, 
                                      /*ObjectType=*/0, EnteringContext,
-                                     Template))
-        if (AnnotateTemplateIdToken(Template, TNK, &SS)) {
+                                     Template)) {
+        // Consume the identifier.
+        ConsumeToken();
+        if (AnnotateTemplateIdToken(Template, TNK, &SS, TemplateName)) {
           // If an unrecoverable error occurred, we need to return true here,
           // because the token stream is in a damaged state.  We may not return
           // a valid identifier.
           return Tok.isNot(tok::identifier);
         }
+      }
     }
 
     // The current token, which is either an identifier or a

Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Tue Nov  3 18:56:37 2009
@@ -2498,8 +2498,13 @@
       Name = ActualTemplate->getDeclName();
     else if (OverloadedFunctionDecl *Ovl = Template.getAsOverloadedFunctionDecl())
       Name = Ovl->getDeclName();
-    else
-      Name = Template.getAsDependentTemplateName()->getName();
+    else {
+      DependentTemplateName *DTN = Template.getAsDependentTemplateName();
+      if (DTN->isIdentifier())
+        Name = DTN->getIdentifier();
+      else
+        Name = Context.DeclarationNames.getCXXOperatorName(DTN->getOperator());
+    }
     
     // Translate the parser's template argument list in our AST format.
     ASTTemplateArgsPtr TemplateArgsPtr(*this,

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Tue Nov  3 18:56:37 2009
@@ -1405,6 +1405,10 @@
     return TemplateTy::make(Context.getDependentTemplateName(Qualifier, 
                                                              Name.Identifier));
     
+  case UnqualifiedId::IK_OperatorFunctionId:
+    return TemplateTy::make(Context.getDependentTemplateName(Qualifier,
+                                             Name.OperatorFunctionId.Operator));
+      
   default:
     break;
   }

Modified: cfe/trunk/lib/Sema/TreeTransform.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/TreeTransform.h?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/TreeTransform.h (original)
+++ cfe/trunk/lib/Sema/TreeTransform.h Tue Nov  3 18:56:37 2009
@@ -605,7 +605,17 @@
                                    const IdentifierInfo &II,
                                    QualType ObjectType);
 
-
+  /// \brief Build a new template name given a nested name specifier and the
+  /// overloaded operator name that is referred to as a template.
+  ///
+  /// By default, performs semantic analysis to determine whether the name can
+  /// be resolved to a specific template, then builds the appropriate kind of
+  /// template name. Subclasses may override this routine to provide different
+  /// behavior.
+  TemplateName RebuildTemplateName(NestedNameSpecifier *Qualifier,
+                                   OverloadedOperatorKind Operator,
+                                   QualType ObjectType);
+  
   /// \brief Build a new compound statement.
   ///
   /// By default, performs semantic analysis to build the new statement.
@@ -1575,9 +1585,14 @@
     else if (OverloadedFunctionDecl *Ovl
                = Template.getAsOverloadedFunctionDecl())
       Name = Ovl->getDeclName();
-    else
-      Name = Template.getAsDependentTemplateName()->getName();
-
+    else {
+      DependentTemplateName *DTN = Template.getAsDependentTemplateName();
+      if (DTN->isIdentifier())
+        Name = DTN->getIdentifier();
+      else
+        Name = SemaRef.Context.DeclarationNames.getCXXOperatorName(
+                                                          DTN->getOperator());
+    }
       return SemaRef.BuildMemberReferenceExpr(/*Scope=*/0, move(Base),
                                               OperatorLoc, OpKind,
                                               TemplateNameLoc, Name, true,
@@ -1873,7 +1888,12 @@
         ObjectType.isNull())
       return Name;
 
-    return getDerived().RebuildTemplateName(NNS, *DTN->getName(), ObjectType);
+    if (DTN->isIdentifier())
+      return getDerived().RebuildTemplateName(NNS, *DTN->getIdentifier(), 
+                                              ObjectType);
+    
+    return getDerived().RebuildTemplateName(NNS, DTN->getOperator(), 
+                                            ObjectType);
   }
 
   if (TemplateDecl *Template = Name.getAsTemplateDecl()) {
@@ -4749,9 +4769,14 @@
 
   // FIXME: This is an ugly hack, which forces the same template name to
   // be looked up multiple times. Yuck!
-  // FIXME: This also won't work for, e.g., x->template operator+<int>
-  TemplateName OrigTemplateName
-    = SemaRef.Context.getDependentTemplateName(0, Name.getAsIdentifierInfo());
+  TemporaryBase Rebase(*this, E->getMemberLoc(), DeclarationName());
+  TemplateName OrigTemplateName;
+  if (const IdentifierInfo *II = Name.getAsIdentifierInfo())
+    OrigTemplateName = SemaRef.Context.getDependentTemplateName(0, II);
+  else
+    OrigTemplateName 
+      = SemaRef.Context.getDependentTemplateName(0, 
+                                               Name.getCXXOverloadedOperator());
 
   TemplateName Template
     = getDerived().TransformTemplateName(OrigTemplateName,
@@ -5195,6 +5220,26 @@
 }
 
 template<typename Derived>
+TemplateName
+TreeTransform<Derived>::RebuildTemplateName(NestedNameSpecifier *Qualifier,
+                                            OverloadedOperatorKind Operator,
+                                            QualType ObjectType) {
+  CXXScopeSpec SS;
+  SS.setRange(SourceRange(getDerived().getBaseLocation()));
+  SS.setScopeRep(Qualifier);
+  UnqualifiedId Name;
+  SourceLocation SymbolLocations[3]; // FIXME: Bogus location information.
+  Name.setOperatorFunctionId(/*FIXME:*/getDerived().getBaseLocation(),
+                             Operator, SymbolLocations);
+  return getSema().ActOnDependentTemplateName(
+                                       /*FIXME:*/getDerived().getBaseLocation(),
+                                              SS,
+                                              Name,
+                                              ObjectType.getAsOpaquePtr())
+           .template getAsVal<TemplateName>();
+}
+  
+template<typename Derived>
 Sema::OwningExprResult
 TreeTransform<Derived>::RebuildCXXOperatorCallExpr(OverloadedOperatorKind Op,
                                                    SourceLocation OpLoc,

Modified: cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp (original)
+++ cfe/trunk/test/SemaCXX/invalid-template-specifier.cpp Tue Nov  3 18:56:37 2009
@@ -8,5 +8,5 @@
 namespace S {}
 template <class X> class Y {
   void x() { S::template y<char>(1); } // expected-error {{does not refer to a template}} \
-                                       // expected-error {{no member named 'y'}}
+                                       // expected-error {{unqualified-id}}
 };

Modified: cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp?rev=85989&r1=85988&r2=85989&view=diff

==============================================================================
--- cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp (original)
+++ cfe/trunk/test/SemaTemplate/operator-function-id-template.cpp Tue Nov  3 18:56:37 2009
@@ -19,9 +19,10 @@
 
 template<typename T>
 void test_op_template(A<T> at, T x) {
-  // FIXME: Not yet implemented.
-  //  const A<T> &atr = at.template operator+<T>(x);
-  //  const A<T> &atr2 = at.A<T>::template operator+<T>(x);
+  const A<T> &atr = at.template operator+<T>(x);
+  const A<T> &atr2 = at.A::template operator+<T>(x);
+  // FIXME: unrelated template-name instantiation issue
+  //  const A<T> &atr3 = at.template A<T>::template operator+<T>(x);
 }
 
 template void test_op_template<float>(A<float>, float);





More information about the cfe-commits mailing list