diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-08-20 22:52:58 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-08-20 22:52:58 +0000 |
commit | 37b372b76a3fafe77186d7e6079e5642e2017478 (patch) | |
tree | f39fcf722618ae3e8c255973417c64ec69ea1871 | |
parent | f800f6c09ed4a71bcb593d6962e0fda2c2845a70 (diff) |
Initial support for parsing and representation of member function templates.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@79570 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | include/clang/Parse/Action.h | 1 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 28 | ||||
-rw-r--r-- | lib/Parse/ParseCXXInlineMethods.cpp | 12 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 26 | ||||
-rw-r--r-- | lib/Parse/ParseTemplate.cpp | 6 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 10 | ||||
-rw-r--r-- | test/SemaTemplate/member-function-template.cpp | 5 |
8 files changed, 66 insertions, 23 deletions
diff --git a/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index 70f5dbb929..50074cd771 100644 --- a/include/clang/Parse/Action.h +++ b/include/clang/Parse/Action.h @@ -1276,6 +1276,7 @@ public: /// specifier on the function. virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, bool Deleted = false) { diff --git a/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 9e785a65ff..2b48d9f212 100644 --- a/include/clang/Parse/Parser.h +++ b/include/clang/Parse/Parser.h @@ -580,18 +580,6 @@ private: } }; - void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); - void DeallocateParsedClasses(ParsingClass *Class); - void PopParsingClass(); - - DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D); - void ParseLexedMethodDeclarations(ParsingClass &Class); - void ParseLexedMethodDefs(ParsingClass &Class); - bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, - CachedTokens &Toks, - tok::TokenKind EarlyAbortIf = tok::unknown, - bool ConsumeFinalToken = true); - /// \brief Contains information about any template-specific /// information that has been parsed prior to parsing declaration /// specifiers. @@ -628,6 +616,19 @@ private: /// instantiation. SourceLocation TemplateLoc; }; + + void PushParsingClass(DeclPtrTy TagOrTemplate, bool TopLevelClass); + void DeallocateParsedClasses(ParsingClass *Class); + void PopParsingClass(); + + DeclPtrTy ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, + const ParsedTemplateInfo &TemplateInfo); + void ParseLexedMethodDeclarations(ParsingClass &Class); + void ParseLexedMethodDefs(ParsingClass &Class); + bool ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, + CachedTokens &Toks, + tok::TokenKind EarlyAbortIf = tok::unknown, + bool ConsumeFinalToken = true); //===--------------------------------------------------------------------===// // C99 6.9: External Definitions. @@ -1157,7 +1158,8 @@ private: AccessSpecifier AS = AS_none); void ParseCXXMemberSpecification(SourceLocation StartLoc, unsigned TagType, DeclPtrTy TagDecl); - void ParseCXXClassMemberDeclaration(AccessSpecifier AS); + void ParseCXXClassMemberDeclaration(AccessSpecifier AS, + const ParsedTemplateInfo &TemplateInfo = ParsedTemplateInfo()); void ParseConstructorInitializer(DeclPtrTy ConstructorDecl); MemInitResult ParseMemInitializer(DeclPtrTy ConstructorDecl); void HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, diff --git a/lib/Parse/ParseCXXInlineMethods.cpp b/lib/Parse/ParseCXXInlineMethods.cpp index ca9fc322da..80feff42d7 100644 --- a/lib/Parse/ParseCXXInlineMethods.cpp +++ b/lib/Parse/ParseCXXInlineMethods.cpp @@ -21,17 +21,23 @@ using namespace clang; /// Declarator is a well formed C++ inline method definition. Now lex its body /// and store its tokens for parsing after the C++ class is complete. Parser::DeclPtrTy -Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { +Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, + const ParsedTemplateInfo &TemplateInfo) { assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && "This isn't a function declarator!"); assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && "Current token not a '{', ':' or 'try'!"); + Action::MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); DeclPtrTy FnD; if (D.getDeclSpec().isFriendSpecified()) + // FIXME: Friend templates FnD = Actions.ActOnFriendDecl(CurScope, &D, /*IsDefinition*/ true); - else - FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0); + else // FIXME: pass template information through + FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, + move(TemplateParams), 0, 0); HandleMemberFunctionDefaultArgs(D, FnD); diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index fd860a4e25..bce9ee0d82 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -905,15 +905,19 @@ void Parser::HandleMemberFunctionDefaultArgs(Declarator& DeclaratorInfo, /// constant-initializer: /// '=' constant-expression /// -void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { +void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, + const ParsedTemplateInfo &TemplateInfo) { // static_assert-declaration if (Tok.is(tok::kw_static_assert)) { + // FIXME: Check for templates SourceLocation DeclEnd; ParseStaticAssertDeclaration(DeclEnd); return; } if (Tok.is(tok::kw_template)) { + assert(!TemplateInfo.TemplateParams && + "Nested template improperly parsed?"); SourceLocation DeclEnd; ParseDeclarationStartingWithTemplate(Declarator::MemberContext, DeclEnd, AS); @@ -925,10 +929,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // __extension__ silences extension warnings in the subexpression. ExtensionRAIIObject O(Diags); // Use RAII to do this. ConsumeToken(); - return ParseCXXClassMemberDeclaration(AS); + return ParseCXXClassMemberDeclaration(AS, TemplateInfo); } if (Tok.is(tok::kw_using)) { + // FIXME: Check for template aliases + // Eat 'using'. SourceLocation UsingLoc = ConsumeToken(); @@ -948,11 +954,12 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { // decl-specifier-seq: // Parse the common declaration-specifiers piece. DeclSpec DS; - ParseDeclarationSpecifiers(DS, ParsedTemplateInfo(), AS, DSC_class); + ParseDeclarationSpecifiers(DS, TemplateInfo, AS, DSC_class); if (Tok.is(tok::semi)) { ConsumeToken(); + // FIXME: Friend templates? if (DS.isFriendSpecified()) Actions.ActOnFriendDecl(CurScope, &DS, /*IsDefinition*/ false); else @@ -996,7 +1003,7 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { return; } - ParseCXXInlineMethodDef(AS, DeclaratorInfo); + ParseCXXInlineMethodDef(AS, DeclaratorInfo, TemplateInfo); return; } } @@ -1059,15 +1066,20 @@ void Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS) { DeclPtrTy ThisDecl; if (DS.isFriendSpecified()) { - // TODO: handle initializers, bitfields, 'delete' + // TODO: handle initializers, bitfields, 'delete', friend templates ThisDecl = Actions.ActOnFriendDecl(CurScope, &DeclaratorInfo, /*IsDefinition*/ false); - } else + } else { + Action::MultiTemplateParamsArg TemplateParams(Actions, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0, + TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0); ThisDecl = Actions.ActOnCXXMemberDeclarator(CurScope, AS, DeclaratorInfo, + move(TemplateParams), BitfieldSize.release(), Init.release(), Deleted); + } if (ThisDecl) DeclsInGroup.push_back(ThisDecl); @@ -1181,6 +1193,8 @@ void Parser::ParseCXXMemberSpecification(SourceLocation RecordLoc, continue; } + // FIXME: Make sure we don't have a template here. + // Parse all the comma separated declarators. ParseCXXClassMemberDeclaration(CurAS); } diff --git a/lib/Parse/ParseTemplate.cpp b/lib/Parse/ParseTemplate.cpp index 23b32d281a..b2b7ed06e2 100644 --- a/lib/Parse/ParseTemplate.cpp +++ b/lib/Parse/ParseTemplate.cpp @@ -151,6 +151,12 @@ Parser::ParseSingleDeclarationAfterTemplate( assert(TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate && "Template information required"); + if (Context == Declarator::MemberContext) { + // We are parsing a member template. + ParseCXXClassMemberDeclaration(AS, TemplateInfo); + return DeclPtrTy::make((void*)0); + } + // Parse the declaration specifiers. DeclSpec DS; // FIXME: Pass TemplateLoc through for explicit template instantiations diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index 26c8434059..f13a87c580 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -2038,6 +2038,7 @@ public: virtual DeclPtrTy ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BitfieldWidth, ExprTy *Init, bool Deleted = false); diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index aa4ac8f1b0..2edfea1172 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -550,6 +550,7 @@ void Sema::ActOnBaseSpecifiers(DeclPtrTy ClassDecl, BaseTy **Bases, /// any. Sema::DeclPtrTy Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, + MultiTemplateParamsArg TemplateParameterLists, ExprTy *BW, ExprTy *InitExpr, bool Deleted) { const DeclSpec &DS = D.getDeclSpec(); DeclarationName Name = GetNameForDeclarator(D); @@ -627,11 +628,13 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, Decl *Member; if (isInstField) { + // FIXME: Check for template parameters! Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, AS); assert(Member && "HandleField never returns null"); } else { - Member = ActOnDeclarator(S, D).getAs<Decl>(); + Member = HandleDeclarator(S, D, move(TemplateParameterLists), false) + .getAs<Decl>(); if (!Member) { if (BitWidth) DeleteExpr(BitWidth); return DeclPtrTy(); @@ -664,6 +667,11 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } Member->setAccess(AS); + + // If we have declared a member function template, set the access of the + // templated declaration as well. + if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>(Member)) + FunTmpl->getTemplatedDecl()->setAccess(AS); } assert((Name || isInstField) && "No identifier for non-field ?"); diff --git a/test/SemaTemplate/member-function-template.cpp b/test/SemaTemplate/member-function-template.cpp new file mode 100644 index 0000000000..69ebec1365 --- /dev/null +++ b/test/SemaTemplate/member-function-template.cpp @@ -0,0 +1,5 @@ +// RUN: clang-cc -fsyntax-only %s + +struct X { + template<typename T> T& f(T); +}; |