diff options
| author | Douglas Gregor <dgregor@apple.com> | 2009-02-17 23:15:12 +0000 |
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2009-02-17 23:15:12 +0000 |
| commit | 67a65640918dc52e362181099bfc9044313a99e6 (patch) | |
| tree | f1addf579c5492a610c1e1982990cc1ac9410ce0 /clang/lib/Parse | |
| parent | 79d10a2f4321b5acd275c7145ff5c56f3429fb10 (diff) | |
| download | bcm5719-llvm-67a65640918dc52e362181099bfc9044313a99e6.tar.gz bcm5719-llvm-67a65640918dc52e362181099bfc9044313a99e6.zip | |
Implement basic parsing and semantic analysis for explicit
specialization of class templates, e.g.,
template<typename T> class X;
template<> class X<int> { /* blah */ };
Each specialization is a different *Decl node (naturally), and can
have different members. We keep track of forward declarations and
definitions as for other class/struct/union types.
This is only the basic framework: we still have to deal with checking
the template headers properly, improving recovery when there are
failures, handling nested name specifiers, etc.
llvm-svn: 64848
Diffstat (limited to 'clang/lib/Parse')
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 4 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseDeclCXX.cpp | 74 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseTemplate.cpp | 153 |
3 files changed, 176 insertions, 55 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 5d601bc4f1f..953b5525625 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -228,7 +228,7 @@ Parser::DeclTy *Parser::ParseDeclaration(unsigned Context) { switch (Tok.getKind()) { case tok::kw_export: case tok::kw_template: - return ParseTemplateDeclaration(Context); + return ParseTemplateDeclarationOrSpecialization(Context); case tok::kw_namespace: return ParseNamespace(Context); case tok::kw_using: @@ -2095,7 +2095,7 @@ void Parser::ParseFunctionDeclarator(SourceLocation LParenLoc, Declarator &D, DS.AddAttributes(AttrList); AttrList = 0; // Only apply the attributes to the first parameter. } - ParseDeclarationSpecifiers(DS); + ParseDeclarationSpecifiers(DS); // Parse the declarator. This is "PrototypeContext", because we must // accept either 'declarator' or 'abstract-declarator' here. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index d6b83f3fb2d..e36bc40bac3 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -310,17 +310,69 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, // Parse the (optional) nested-name-specifier. CXXScopeSpec SS; if (getLang().CPlusPlus && ParseOptionalCXXScopeSpecifier(SS)) { + // FIXME: can we get a class template specialization or + // template-id token here? if (Tok.isNot(tok::identifier)) Diag(Tok, diag::err_expected_ident); } - // Parse the (optional) class name. - // FIXME: Alternatively, parse a simple-template-id. + + // These variables encode the simple-template-id that we might end + // up parsing below. We don't translate this into a type + // automatically because (1) we want to create a separate + // declaration for each specialization, and (2) we want to retain + // more information about source locations that types provide. + DeclTy *Template = 0; + SourceLocation LAngleLoc, RAngleLoc; + TemplateArgList TemplateArgs; + TemplateArgIsTypeList TemplateArgIsType; + TemplateArgLocationList TemplateArgLocations; + ASTTemplateArgsPtr TemplateArgsPtr(Actions, 0, 0, 0); + + + // Parse the (optional) class name or simple-template-id. IdentifierInfo *Name = 0; SourceLocation NameLoc; if (Tok.is(tok::identifier)) { Name = Tok.getIdentifierInfo(); NameLoc = ConsumeToken(); + + if (Tok.is(tok::less)) { + // This is a simple-template-id. + Action::TemplateNameKind TNK + = Actions.isTemplateName(*Name, CurScope, Template, &SS); + + bool Invalid = false; + + // Parse the enclosed template argument list. + if (TNK != Action::TNK_Non_template) + Invalid = ParseTemplateIdAfterTemplateName(Template, NameLoc, + &SS, true, LAngleLoc, + TemplateArgs, + TemplateArgIsType, + TemplateArgLocations, + RAngleLoc); + + TemplateArgsPtr.reset(&TemplateArgs[0], &TemplateArgIsType[0], + TemplateArgs.size()); + + if (TNK != Action::TNK_Class_template) { + // The template-name in the simple-template-id refers to + // something other than a class template. Give an appropriate + // error message and skip to the ';'. + SourceRange Range(NameLoc); + if (SS.isNotEmpty()) + Range.setBegin(SS.getBeginLoc()); + else if (!Invalid) + + Diag(LAngleLoc, diag::err_template_spec_syntax_non_template) + << Name << static_cast<int>(TNK) << Range; + + DS.SetTypeSpecError(); + SkipUntil(tok::semi, false, true); + return; + } + } } // There are three options here. If we have 'struct foo;', then @@ -347,7 +399,23 @@ void Parser::ParseClassSpecifier(DeclSpec &DS, // Create the tag portion of the class or class template. DeclTy *TagOrTempDecl; - if (TemplateParams && TK != Action::TK_Reference) + if (Template && TK != Action::TK_Reference) + // Explicit specialization or class template partial + // specialization. Let semantic analysis decide. + + // FIXME: we want a source range covering the simple-template-id. + TagOrTempDecl + = Actions.ActOnClassTemplateSpecialization(CurScope, TagType, TK, + StartLoc, SS, /*Range*/ + Template, NameLoc, + LAngleLoc, TemplateArgsPtr, + &TemplateArgLocations[0], + RAngleLoc, Attr, + Action::MultiTemplateParamsArg(Actions, + TemplateParams? &(*TemplateParams)[0] : 0, + TemplateParams? TemplateParams->size() : 0)); + + else if (TemplateParams && TK != Action::TK_Reference) TagOrTempDecl = Actions.ActOnClassTemplate(CurScope, TagType, TK, StartLoc, SS, Name, NameLoc, Attr, Action::MultiTemplateParamsArg(Actions, diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp index 742453046b3..52824f51c13 100644 --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -19,12 +19,23 @@ using namespace clang; -/// ParseTemplateDeclaration - Parse a template declaration, which includes -/// the template parameter list and either a function of class declaration. +/// \brief Parse a template declaration or an explicit specialization. +/// +/// Template declarations include one or more template parameter lists +/// and either the function or class template declaration. Explicit +/// specializations contain one or more 'template < >' prefixes +/// followed by a (possibly templated) declaration. Since the +/// syntactic form of both features is nearly identical, we parse all +/// of the template headers together and let semantic analysis sort +/// the declarations from the explicit specializations. /// /// template-declaration: [C++ temp] /// 'export'[opt] 'template' '<' template-parameter-list '>' declaration -Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) { +/// +/// explicit-specialization: [ C++ temp.expl.spec] +/// 'template' '<' '>' declaration +Parser::DeclTy * +Parser::ParseTemplateDeclarationOrSpecialization(unsigned Context) { assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) && "Token does not start a template declaration."); @@ -40,7 +51,7 @@ Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) { // // We parse multiple levels non-recursively so that we can build a // single data structure containing all of the template parameter - // lists easily differentiate between the case above and: + // lists to easily differentiate between the case above and: // // template<typename T> // class A { @@ -370,6 +381,68 @@ Parser::ParseNonTypeTemplateParameter(unsigned Depth, unsigned Position) { return Param; } +/// \brief Parses a template-id that after the template name has +/// already been parsed. +/// +/// This routine takes care of parsing the enclosed template argument +/// list ('<' template-parameter-list [opt] '>') and placing the +/// results into a form that can be transferred to semantic analysis. +/// +/// \param Template the template declaration produced by isTemplateName +/// +/// \param TemplateNameLoc the source location of the template name +/// +/// \param SS if non-NULL, the nested-name-specifier preceding the +/// template name. +/// +/// \param ConsumeLastToken if true, then we will consume the last +/// token that forms the template-id. Otherwise, we will leave the +/// last token in the stream (e.g., so that it can be replaced with an +/// annotation token). +bool +Parser::ParseTemplateIdAfterTemplateName(DeclTy *Template, + SourceLocation TemplateNameLoc, + const CXXScopeSpec *SS, + bool ConsumeLastToken, + SourceLocation &LAngleLoc, + TemplateArgList &TemplateArgs, + TemplateArgIsTypeList &TemplateArgIsType, + TemplateArgLocationList &TemplateArgLocations, + SourceLocation &RAngleLoc) { + assert(Tok.is(tok::less) && "Must have already parsed the template-name"); + + // Consume the '<'. + LAngleLoc = ConsumeToken(); + + // Parse the optional template-argument-list. + bool Invalid = false; + { + GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); + if (Tok.isNot(tok::greater)) + Invalid = ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType, + TemplateArgLocations); + + if (Invalid) { + // Try to find the closing '>'. + SkipUntil(tok::greater, true, !ConsumeLastToken); + + return true; + } + } + + if (Tok.isNot(tok::greater)) + return true; + + // Determine the location of the '>'. Only consume this token if the + // caller asked us to. + RAngleLoc = Tok.getLocation(); + + if (ConsumeLastToken) + ConsumeToken(); + + return false; +} + /// 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. @@ -382,46 +455,44 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, // Consume the template-name. SourceLocation TemplateNameLoc = ConsumeToken(); - // Consume the '<'. - SourceLocation LAngleLoc = ConsumeToken(); - - // Parse the optional template-argument-list. + // Parse the enclosed template argument list. + SourceLocation LAngleLoc, RAngleLoc; TemplateArgList TemplateArgs; TemplateArgIsTypeList TemplateArgIsType; TemplateArgLocationList TemplateArgLocations; + bool Invalid = ParseTemplateIdAfterTemplateName(Template, TemplateNameLoc, + SS, false, LAngleLoc, + TemplateArgs, + TemplateArgIsType, + TemplateArgLocations, + RAngleLoc); - { - GreaterThanIsOperatorScope G(GreaterThanIsOperator, false); - if (Tok.isNot(tok::greater) && - ParseTemplateArgumentList(TemplateArgs, TemplateArgIsType, - TemplateArgLocations)) { - // Try to find the closing '>'. - SkipUntil(tok::greater, true, true); + ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0], + &TemplateArgIsType[0], + TemplateArgs.size()); - // Clean up any template arguments that we successfully parsed. - ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0], - &TemplateArgIsType[0], - TemplateArgs.size()); - - return; - } - } - - if (Tok.isNot(tok::greater)) - return; + if (Invalid) // FIXME: How to recover from a broken template-id? + 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(); - // Build the annotation token. - if (TNK == Action::TNK_Function_template) { + if (TNK == Action::TNK_Class_template) { + Action::TypeResult Type + = Actions.ActOnClassTemplateId(Template, TemplateNameLoc, + LAngleLoc, TemplateArgsPtr, + &TemplateArgLocations[0], + RAngleLoc, SS); + if (Type.isInvalid()) // FIXME: better recovery? + return; + + Tok.setKind(tok::annot_typename); + Tok.setAnnotationValue(Type.get()); + } else { // This is a function template. We'll be building a template-id // annotation token. Tok.setKind(tok::annot_template_id); TemplateIdAnnotation *TemplateId = (TemplateIdAnnotation *)malloc(sizeof(TemplateIdAnnotation) + - sizeof(void*) * TemplateArgs.size()); + sizeof(void*) * TemplateArgs.size()); TemplateId->TemplateNameLoc = TemplateNameLoc; TemplateId->Template = Template; TemplateId->LAngleLoc = LAngleLoc; @@ -430,24 +501,6 @@ void Parser::AnnotateTemplateIdToken(DeclTy *Template, TemplateNameKind TNK, for (unsigned Arg = 0, ArgEnd = TemplateArgs.size(); Arg != ArgEnd; ++Arg) Args[Arg] = TemplateArgs[Arg]; Tok.setAnnotationValue(TemplateId); - } else { - // This is a type template, e.g., a class template, template - // template parameter, or template alias. We'll be building a - // "typename" annotation token. - ASTTemplateArgsPtr TemplateArgsPtr(Actions, &TemplateArgs[0], - &TemplateArgIsType[0], - TemplateArgs.size()); - TypeTy *Ty - = Actions.ActOnClassTemplateSpecialization(Template, TemplateNameLoc, - LAngleLoc, TemplateArgsPtr, - &TemplateArgLocations[0], - RAngleLoc, SS); - - if (!Ty) // Something went wrong; don't annotate - return; - - Tok.setKind(tok::annot_typename); - Tok.setAnnotationValue(Ty); } // Common fields for the annotation token |

