summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDouglas Gregor <dgregor@apple.com>2009-08-20 22:52:58 +0000
committerDouglas Gregor <dgregor@apple.com>2009-08-20 22:52:58 +0000
commit37b372b76a3fafe77186d7e6079e5642e2017478 (patch)
treef39fcf722618ae3e8c255973417c64ec69ea1871
parentf800f6c09ed4a71bcb593d6962e0fda2c2845a70 (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.h1
-rw-r--r--include/clang/Parse/Parser.h28
-rw-r--r--lib/Parse/ParseCXXInlineMethods.cpp12
-rw-r--r--lib/Parse/ParseDeclCXX.cpp26
-rw-r--r--lib/Parse/ParseTemplate.cpp6
-rw-r--r--lib/Sema/Sema.h1
-rw-r--r--lib/Sema/SemaDeclCXX.cpp10
-rw-r--r--test/SemaTemplate/member-function-template.cpp5
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);
+};