diff options
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/Parse/MinimalAction.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 22 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 108 | ||||
| -rw-r--r-- | clang/lib/Parse/Parser.cpp | 45 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 2 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaTemplate.cpp | 36 | 
6 files changed, 203 insertions, 20 deletions
diff --git a/clang/lib/Parse/MinimalAction.cpp b/clang/lib/Parse/MinimalAction.cpp index 583781056e0..c4e7ecc0c37 100644 --- a/clang/lib/Parse/MinimalAction.cpp +++ b/clang/lib/Parse/MinimalAction.cpp @@ -73,6 +73,16 @@ bool MinimalAction::isCurrentClassName(const IdentifierInfo &, Scope *,    return false;  } +  /// isTemplateName - Determines whether the identifier II is a +  /// template name in the current scope, and returns the template +  /// declaration if II names a template. An optional CXXScope can be +  /// passed to indicate the C++ scope in which the identifier will be +  /// found.  +Action::DeclTy *MinimalAction::isTemplateName(IdentifierInfo &II, Scope *S, +                                              const CXXScopeSpec *SS ) { +  return 0; +} +  /// ActOnDeclarator - If this is a typedef declarator, we modify the  /// IdentifierInfo::FETokenInfo field to keep track of this fact, until S is  /// popped. diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 407aa9c7d96..16e7e774aa9 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1452,13 +1452,27 @@ void Parser::ParseDirectDeclarator(Declarator &D) {        if (Tok.is(tok::identifier)) {          assert(Tok.getIdentifierInfo() && "Not an identifier?"); -        // Determine whether this identifier is a C++ constructor name or -        // a normal identifier. -        if (Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope)) { + +        // If this identifier is followed by a '<', we may have a template-id. +        DeclTy *Template; +        if (getLang().CPlusPlus && NextToken().is(tok::less) && +            (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(),  +                                               CurScope))) { +          IdentifierInfo *II = Tok.getIdentifierInfo(); +          AnnotateTemplateIdToken(Template, 0); +          // FIXME: Set the declarator to a template-id. How? I don't +          // know... for now, just use the identifier. +          D.SetIdentifier(II, Tok.getLocation()); +        } +        // If this identifier is the name of the current class, it's a +        // constructor name.  +        else if (getLang().CPlusPlus && +                 Actions.isCurrentClassName(*Tok.getIdentifierInfo(), CurScope))            D.setConstructor(Actions.isTypeName(*Tok.getIdentifierInfo(),                                                CurScope),                             Tok.getLocation()); -        } else +        // This is a normal identifier. +        else            D.SetIdentifier(Tok.getIdentifierInfo(), Tok.getLocation());          ConsumeToken();          goto PastIdentifier; diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index d21dc4aa6d6..5d0c4b5350a 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -46,8 +46,19 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {    // Try to parse the template parameters, and the declaration if    // successful.    DeclTy *TemplateDecl = 0; -  if(ParseTemplateParameters(0)) +  if (Tok.is(tok::less) && NextToken().is(tok::greater)) { +    // This is a template specialization. Just consume the angle +    // brackets and parse the declaration or function definition that +    // follows. +    // FIXME: Record somehow that we're in an explicit specialization. +    ConsumeToken(); +    ConsumeToken(); +    TemplateParmScope.Exit();      TemplateDecl = ParseDeclarationOrFunctionDefinition(); +  } else { +    if(ParseTemplateParameters(0)) +      TemplateDecl = ParseDeclarationOrFunctionDefinition(); +  }    return TemplateDecl;  } @@ -243,7 +254,7 @@ Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {  /// ParseNonTypeTemplateParameter - Handle the parsing of non-type  /// template parameters (e.g., in "template<int Size> class array;").  - +///  ///       template-parameter:  ///         ...  ///         parameter-declaration @@ -289,3 +300,96 @@ Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {    return Param;  } + +/// AnnotateTemplateIdToken - The current token is an identifier that +/// refers to the template declaration Template, and is followed by a +/// '<'. Turn this template-id into a template-id annotation token. +void Parser::AnnotateTemplateIdToken(DeclTy *Template, const CXXScopeSpec *SS) { +  assert(getLang().CPlusPlus && "Can only annotate template-ids in C++"); +  assert(Template && Tok.is(tok::identifier) && NextToken().is(tok::less) && +         "Parser isn't at the beginning of a template-id"); + +  // Consume the template-name. +  SourceLocation TemplateNameLoc = ConsumeToken(); + +  // Consume the '<'. +  SourceLocation LAngleLoc = ConsumeToken(); + +  // Parse the optional template-argument-list. +  TemplateArgList TemplateArgs; +  if (Tok.isNot(tok::greater) && ParseTemplateArgumentList(TemplateArgs)) { +    // Try to find the closing '>'. +    SkipUntil(tok::greater, true, true); + +    // FIXME: What's our recovery strategy for failed template-argument-lists? +    return; +  } + +  if (Tok.isNot(tok::greater)) +    return; + +  // Determine the location of the '>'. We won't actually consume this +  // token, because we'll be replacing it with the template-id. +  SourceLocation RAngleLoc = Tok.getLocation(); +   +  Tok.setKind(tok::annot_template_id); +  Tok.setAnnotationEndLoc(RAngleLoc); +  Tok.setLocation(TemplateNameLoc); +  if (SS && SS->isNotEmpty()) +    Tok.setLocation(SS->getBeginLoc()); + +  TemplateIdAnnotation *TemplateId  +    = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) +  +                                  sizeof(TemplateArgTy*) * TemplateArgs.size()); +  TemplateId->TemplateNameLoc = TemplateNameLoc; +  TemplateId->Template = Template; +  TemplateId->LAngleLoc = LAngleLoc; +  TemplateId->NumArgs = TemplateArgs.size(); +  TemplateArgTy **Args = (TemplateArgTy**)(TemplateId + 1); +  for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) +    Args[Arg] = TemplateArgs[Arg]; +  Tok.setAnnotationValue(TemplateId); + +  // In case the tokens were cached, have Preprocessor replace them with the +  // annotation token. +  PP.AnnotateCachedTokens(Tok); +} + +/// ParseTemplateArgument - Parse a C++ template argument (C++ [temp.names]). +/// +///       template-argument: [C++ 14.2] +///         assignment-expression +///         type-id +///         id-expression +Parser::OwningTemplateArgResult Parser::ParseTemplateArgument() { +  // FIXME: Implement this! +  return TemplateArgError(); +} + +/// ParseTemplateArgumentList - Parse a C++ template-argument-list +/// (C++ [temp.names]). Returns true if there was an error. +/// +///       template-argument-list: [C++ 14.2] +///         template-argument +///         template-argument-list ',' template-argument +bool Parser::ParseTemplateArgumentList(TemplateArgList &TemplateArgs) { +  while (true) { +    OwningTemplateArgResult Arg = ParseTemplateArgument(); +    if (Arg.isInvalid()) { +      SkipUntil(tok::comma, tok::greater, true, true); +      return true; +    } +    else +      TemplateArgs.push_back(Arg.release()); +     +    // If the next token is a comma, consume it and keep reading +    // arguments. +    if (Tok.isNot(tok::comma)) break; + +    // Consume the comma. +    ConsumeToken(); +  } + +  return Tok.isNot(tok::greater); +} + diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 058182eee6b..48b0d5f422e 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -722,6 +722,7 @@ Parser::OwningExprResult Parser::ParseSimpleAsm() {  /// specifier, and another one to get the actual type inside  /// ParseDeclarationSpecifiers).  void Parser::TryAnnotateTypeOrScopeToken() { +  // FIXME: what about template-ids?    if (Tok.is(tok::annot_qualtypename) || Tok.is(tok::annot_cxxscope))      return; @@ -730,23 +731,39 @@ void Parser::TryAnnotateTypeOrScopeToken() {      MaybeParseCXXScopeSpecifier(SS);    if (Tok.is(tok::identifier)) { -    TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS); -    if (Ty) { -      // This is a typename. Replace the current token in-place with an -      // annotation type token. -      Tok.setKind(tok::annot_qualtypename); -      Tok.setAnnotationValue(Ty); -      Tok.setAnnotationEndLoc(Tok.getLocation()); -      if (SS.isNotEmpty()) // it was a C++ qualified type name. -        Tok.setLocation(SS.getBeginLoc()); - -      // In case the tokens were cached, have Preprocessor replace them with the -      // annotation token. -      PP.AnnotateCachedTokens(Tok); -      return; +    DeclTy *Template = 0; +    // If this is a template-id, annotate the template-id token. +    if (getLang().CPlusPlus && NextToken().is(tok::less) && +        (Template = Actions.isTemplateName(*Tok.getIdentifierInfo(), CurScope,  +                                           &SS))) +      AnnotateTemplateIdToken(Template, &SS); +    else { +      // Determine whether the identifier is a type name. +      TypeTy *Ty = Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope, &SS); +      if (Ty) { +        // This is a typename. Replace the current token in-place with an +        // annotation type token. +        Tok.setKind(tok::annot_qualtypename); +        Tok.setAnnotationValue(Ty); +        Tok.setAnnotationEndLoc(Tok.getLocation()); +        if (SS.isNotEmpty()) // it was a C++ qualified type name. +          Tok.setLocation(SS.getBeginLoc()); +         +        // In case the tokens were cached, have Preprocessor replace +        // them with the annotation token. +        PP.AnnotateCachedTokens(Tok); +        return; +      }      } + +    // We either have an identifier that is not a type name or we have +    // just created a template-id that might be a type name. Both +    // cases will be handled below.    } +  // FIXME: check for a template-id token here, and look it up if it +  // names a type. +    if (SS.isNotEmpty()) {      // A C++ scope specifier that isn't followed by a typename.      // Push the current token back into the token stream (or revert it if it is diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 66230314c0f..0534f3dce23 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -1005,6 +1005,8 @@ public:    //===--------------------------------------------------------------------===//    // C++ Templates [C++ 14]    // +  virtual DeclTy *isTemplateName(IdentifierInfo &II, Scope *S, +                                 const CXXScopeSpec *SS = 0);    bool DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);    virtual DeclTy *ActOnTypeParameter(Scope *S, bool Typename,   				     SourceLocation KeyLoc, diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 2dcb9fe3361..d300f283b66 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -18,6 +18,42 @@  using namespace clang; +/// isTemplateName - Determines whether the identifier II is a +/// template name in the current scope, and returns the template +/// declaration if II names a template. An optional CXXScope can be +/// passed to indicate the C++ scope in which the identifier will be +/// found.  +Sema::DeclTy *Sema::isTemplateName(IdentifierInfo &II, Scope *S, +                                   const CXXScopeSpec *SS) { +  DeclContext *DC = 0; +  if (SS) { +    if (SS->isInvalid()) +      return 0; +    DC = static_cast<DeclContext*>(SS->getScopeRep()); +  } +  Decl *IIDecl = LookupDecl(&II, Decl::IDNS_Ordinary, S, DC, false); + +  if (IIDecl) { +    // FIXME: We need to represent templates via some kind of +    // TemplateDecl, because what follows is a hack that only works in +    // one specific case. +    if (FunctionDecl *FD = dyn_cast<FunctionDecl>(IIDecl)) { +      if (FD->getType()->isDependentType()) +        return FD; +    } else if (OverloadedFunctionDecl *Ovl  +                 = dyn_cast<OverloadedFunctionDecl>(IIDecl)) { +      for (OverloadedFunctionDecl::function_iterator F = Ovl->function_begin(), +                                                  FEnd = Ovl->function_end(); +           F != FEnd; ++F) { +        if ((*F)->getType()->isDependentType()) +          return Ovl; +      } +    } +    return 0; +  } +  return 0; +} +  /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining  /// that the template parameter 'PrevDecl' is being shadowed by a new  /// declaration at location Loc. Returns true to indicate that this is  | 

