Introduce a new class, UnqualifiedId, that provides a parsed
representation of a C++ unqualified-id, along with a single parsing
function (Parser::ParseUnqualifiedId) that will parse all of the
various forms of unqualified-id in C++.

Replace the representation of the declarator name in Declarator with
the new UnqualifiedId class, simplifying declarator-id parsing
considerably and providing more source-location information to
Sema. In the future, I hope to migrate all of the other
unqualified-id-parsing code over to this single representation, then
begin to merge actions that are currently only different because we
didn't have a unqualified notion of the name in the parser.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@85851 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index fa65156..dc79741 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -14,6 +14,8 @@
 #include "clang/Parse/ParseDiagnostic.h"
 #include "clang/Parse/Parser.h"
 #include "clang/Parse/DeclSpec.h"
+#include "llvm/Support/ErrorHandling.h"
+
 using namespace clang;
 
 /// \brief Parse global scope or nested-name-specifier if present.
@@ -761,6 +763,417 @@
   return false;
 }
 
+/// \brief Finish parsing a C++ unqualified-id that is a template-id of
+/// some form. 
+///
+/// This routine is invoked when a '<' is encountered after an identifier or
+/// operator-function-id is parsed by \c ParseUnqualifiedId() to determine
+/// whether the unqualified-id is actually a template-id. This routine will
+/// then parse the template arguments and form the appropriate template-id to
+/// return to the caller.
+///
+/// \param SS the nested-name-specifier that precedes this template-id, if
+/// we're actually parsing a qualified-id.
+///
+/// \param Name for constructor and destructor names, this is the actual
+/// identifier that may be a template-name.
+///
+/// \param NameLoc the location of the class-name in a constructor or 
+/// destructor.
+///
+/// \param EnteringContext whether we're entering the scope of the 
+/// nested-name-specifier.
+///
+/// \param Id as input, describes the template-name or operator-function-id
+/// that precedes the '<'. If template arguments were parsed successfully,
+/// will be updated with the template-id.
+/// 
+/// \returns true if a parse error occurred, false otherwise.
+bool Parser::ParseUnqualifiedIdTemplateId(CXXScopeSpec &SS,
+                                          IdentifierInfo *Name,
+                                          SourceLocation NameLoc,
+                                          bool EnteringContext,
+                                          UnqualifiedId &Id) {
+  assert(Tok.is(tok::less) && "Expected '<' to finish parsing a template-id");
+  
+  TemplateTy Template;
+  TemplateNameKind TNK = TNK_Non_template;
+  switch (Id.getKind()) {
+  case UnqualifiedId::IK_Identifier:
+    TNK = Actions.isTemplateName(CurScope, *Id.Identifier, Id.StartLocation, 
+                                 &SS, /*ObjectType=*/0, EnteringContext,
+                                 Template);
+    break;
+      
+  case UnqualifiedId::IK_OperatorFunctionId: {
+    // FIXME: Temporary hack: warn that we are completely ignoring the 
+    // template arguments for now.
+    // Parse the enclosed template argument list.
+    SourceLocation LAngleLoc, RAngleLoc;
+    TemplateArgList TemplateArgs;
+    TemplateArgIsTypeList TemplateArgIsType;
+    TemplateArgLocationList TemplateArgLocations;
+    if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
+                                         &SS, true, LAngleLoc,
+                                         TemplateArgs,
+                                         TemplateArgIsType,
+                                         TemplateArgLocations,
+                                         RAngleLoc))
+      return true;
+    
+    Diag(Id.StartLocation, diag::warn_operator_template_id_ignores_args)
+      << SourceRange(LAngleLoc, RAngleLoc);
+    break;
+  }
+      
+  case UnqualifiedId::IK_ConstructorName:
+    TNK = Actions.isTemplateName(CurScope, *Name, NameLoc, 
+                                 &SS, /*ObjectType=*/0, EnteringContext,
+                                 Template);
+    break;
+      
+  case UnqualifiedId::IK_DestructorName:
+    TNK = Actions.isTemplateName(CurScope, *Name, NameLoc,
+                                 &SS, /*ObjectType=*/0, EnteringContext,
+                                 Template);
+    break;
+      
+  default:
+    return false;
+  }
+  
+  if (TNK == TNK_Non_template)
+    return false;
+  
+  // Parse the enclosed template argument list.
+  SourceLocation LAngleLoc, RAngleLoc;
+  TemplateArgList TemplateArgs;
+  TemplateArgIsTypeList TemplateArgIsType;
+  TemplateArgLocationList TemplateArgLocations;
+  if (ParseTemplateIdAfterTemplateName(Template, Id.StartLocation,
+                                       &SS, true, LAngleLoc,
+                                       TemplateArgs,
+                                       TemplateArgIsType,
+                                       TemplateArgLocations,
+                                       RAngleLoc))
+    return true;
+  
+  if (Id.getKind() == UnqualifiedId::IK_Identifier ||
+      Id.getKind() == UnqualifiedId::IK_OperatorFunctionId) {
+    // Form a parsed representation of the template-id to be stored in the
+    // UnqualifiedId.
+    TemplateIdAnnotation *TemplateId
+      = TemplateIdAnnotation::Allocate(TemplateArgs.size());
+
+    if (Id.getKind() == UnqualifiedId::IK_Identifier) {
+      TemplateId->Name = Id.Identifier;
+      TemplateId->TemplateNameLoc = Id.StartLocation;
+    } else {
+      // FIXME: Handle IK_OperatorFunctionId
+    }
+
+    TemplateId->Template = Template.getAs<void*>();
+    TemplateId->Kind = TNK;
+    TemplateId->LAngleLoc = LAngleLoc;
+    TemplateId->RAngleLoc = RAngleLoc;
+    void **Args = TemplateId->getTemplateArgs();
+    bool *ArgIsType = TemplateId->getTemplateArgIsType();
+    SourceLocation *ArgLocs = TemplateId->getTemplateArgLocations();
+    for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); 
+         Arg != ArgEnd; ++Arg) {
+      Args[Arg] = TemplateArgs[Arg];
+      ArgIsType[Arg] = TemplateArgIsType[Arg];
+      ArgLocs[Arg] = TemplateArgLocations[Arg];
+    }
+    
+    Id.setTemplateId(TemplateId);
+    return false;
+  }
+
+  // Bundle the template arguments together.
+  ASTTemplateArgsPtr TemplateArgsPtr(Actions, TemplateArgs.data(),
+                                     TemplateArgIsType.data(),
+                                     TemplateArgs.size());
+  
+  // Constructor and destructor names.
+  Action::TypeResult Type
+    = Actions.ActOnTemplateIdType(Template, NameLoc,
+                                  LAngleLoc, TemplateArgsPtr,
+                                  &TemplateArgLocations[0],
+                                  RAngleLoc);
+  if (Type.isInvalid())
+    return true;
+  
+  if (Id.getKind() == UnqualifiedId::IK_ConstructorName)
+    Id.setConstructorName(Type.get(), NameLoc, RAngleLoc);
+  else
+    Id.setDestructorName(Id.StartLocation, Type.get(), RAngleLoc);
+  
+  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
+///
+///       operator-function-id: [C++ 13.5]
+///         'operator' operator
+///
+/// operator: one of
+///            new   delete  new[]   delete[]
+///            +     -    *  /    %  ^    &   |   ~
+///            !     =    <  >    += -=   *=  /=  %=
+///            ^=    &=   |= <<   >> >>= <<=  ==  !=
+///            <=    >=   && ||   ++ --   ,   ->* ->
+///            ()    []
+///
+///       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]
+/// \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.
+///
+/// \param Result on a successful parse, contains the parsed unqualified-id.
+///
+/// \returns true if parsing fails, false otherwise.
+bool Parser::ParseUnqualifiedId(CXXScopeSpec &SS, bool EnteringContext,
+                                bool AllowDestructorName,
+                                bool AllowConstructorName,
+                                UnqualifiedId &Result) {
+  // unqualified-id:
+  //   identifier
+  //   template-id (when it hasn't already been annotated)
+  if (Tok.is(tok::identifier)) {
+    // Consume the identifier.
+    IdentifierInfo *Id = Tok.getIdentifierInfo();
+    SourceLocation IdLoc = ConsumeToken();
+
+    if (AllowConstructorName && 
+        Actions.isCurrentClassName(*Id, CurScope, &SS)) {
+      // We have parsed a constructor name.
+      Result.setConstructorName(Actions.getTypeName(*Id, IdLoc, CurScope,
+                                                    &SS, false),
+                                IdLoc, IdLoc);
+    } else {
+      // We have parsed an identifier.
+      Result.setIdentifier(Id, IdLoc);      
+    }
+
+    // If the next token is a '<', we may have a template.
+    if (Tok.is(tok::less))
+      return ParseUnqualifiedIdTemplateId(SS, Id, IdLoc, EnteringContext, 
+                                          Result);
+    
+    return false;
+  }
+  
+  // unqualified-id:
+  //   template-id (already parsed and annotated)
+  if (Tok.is(tok::annot_template_id)) {
+    // FIXME: Could this be a constructor name???
+    
+    // We have already parsed a template-id; consume the annotation token as
+    // our unqualified-id.
+    Result.setTemplateId(
+                  static_cast<TemplateIdAnnotation*>(Tok.getAnnotationValue()));
+    ConsumeToken();
+    return false;
+  }
+  
+  // unqualified-id:
+  //   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, 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))
+      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;
+  }
+  
+  if ((AllowDestructorName || SS.isSet()) && Tok.is(tok::tilde)) {
+    // C++ [expr.unary.op]p10:
+    //   There is an ambiguity in the unary-expression ~X(), where X is a 
+    //   class-name. The ambiguity is resolved in favor of treating ~ as a 
+    //    unary complement rather than treating ~X as referring to a destructor.
+    
+    // Parse the '~'.
+    SourceLocation TildeLoc = ConsumeToken();
+    
+    // Parse the class-name.
+    if (Tok.isNot(tok::identifier)) {
+      Diag(Tok, diag::err_destructor_class_name);
+      return true;
+    }
+
+    // Parse the class-name (or template-name in a simple-template-id).
+    IdentifierInfo *ClassName = Tok.getIdentifierInfo();
+    SourceLocation ClassNameLoc = ConsumeToken();
+    
+    // Note that this is a destructor name.
+    Action::TypeTy *Ty = Actions.getTypeName(*ClassName, ClassNameLoc,
+                                             CurScope, &SS);
+    if (!Ty) {
+      Diag(ClassNameLoc, diag::err_destructor_class_name);
+      return true;
+    }
+    
+    Result.setDestructorName(TildeLoc, Ty, ClassNameLoc);
+    
+    if (Tok.is(tok::less))
+      return ParseUnqualifiedIdTemplateId(SS, ClassName, ClassNameLoc,
+                                          EnteringContext, Result);
+
+    return false;
+  }
+  
+  Diag(Tok, diag::err_expected_unqualified_id);
+  return true;
+}
+
 /// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
 /// operator name (C++ [over.oper]). If successful, returns the
 /// predefined identifier that corresponds to that overloaded