blob: b20799150ccbb6f11d7635d73cb85b4b57e9df31 [file] [log] [blame]
Douglas Gregoradcac882008-12-01 23:54:00 +00001//===--- ParseTemplate.cpp - Template Parsing -----------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements parsing of C++ templates.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Parse/Parser.h"
15#include "clang/Basic/Diagnostic.h"
16#include "clang/Parse/DeclSpec.h"
17#include "clang/Parse/Scope.h"
Sebastian Redl0e9eabc2008-12-09 13:15:23 +000018#include "AstGuard.h"
Douglas Gregoradcac882008-12-01 23:54:00 +000019
20using namespace clang;
21
22/// ParseTemplateDeclaration - Parse a template declaration, which includes
23/// the template parameter list and either a function of class declaration.
24///
25/// template-declaration: [C++ temp]
26/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
27Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
28 assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
29 "Token does not start a template declaration.");
30
31 // Consume the optional export token, if it exists, followed by the
32 // namespace token.
33 bool isExported = false;
34 if(Tok.is(tok::kw_export)) {
35 SourceLocation ExportLoc = ConsumeToken();
36 if(!Tok.is(tok::kw_template)) {
37 Diag(Tok.getLocation(), diag::err_expected_template);
38 return 0;
39 }
40 isExported = true;
41 }
42 SourceLocation TemplateLoc = ConsumeToken();
43
Douglas Gregor26236e82008-12-02 00:41:28 +000044 // Enter template-parameter scope.
Douglas Gregor72c3f312008-12-05 18:15:24 +000045 EnterScope(Scope::TemplateParamScope);
Douglas Gregor26236e82008-12-02 00:41:28 +000046
47 // Try to parse the template parameters, and the declaration if
48 // successful.
49 DeclTy *TemplateDecl = 0;
50 if(ParseTemplateParameters(0))
51 TemplateDecl = ParseDeclarationOrFunctionDefinition();
52
53 // Leave template-parameter scope.
54 ExitScope();
55
56 return TemplateDecl;
Douglas Gregoradcac882008-12-01 23:54:00 +000057}
58
59/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
60/// angle brackets.
61bool Parser::ParseTemplateParameters(DeclTy* TmpDecl) {
62 // Get the template parameter list.
63 if(!Tok.is(tok::less)) {
64 Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
65 return false;
66 }
67 ConsumeToken();
68
69 // Try to parse the template parameter list.
70 if(ParseTemplateParameterList(0)) {
71 if(!Tok.is(tok::greater)) {
72 Diag(Tok.getLocation(), diag::err_expected_greater);
73 return false;
74 }
75 ConsumeToken();
76 }
77 return true;
78}
79
80/// ParseTemplateParameterList - Parse a template parameter list. If
81/// the parsing fails badly (i.e., closing bracket was left out), this
82/// will try to put the token stream in a reasonable position (closing
83/// a statement, etc.) and return false.
84///
85/// template-parameter-list: [C++ temp]
86/// template-parameter
87/// template-parameter-list ',' template-parameter
88bool Parser::ParseTemplateParameterList(DeclTy* TmpDecl) {
89 // FIXME: For now, this is just going to consume the template parameters.
90 // Eventually, we should pass the template decl AST node as a parameter and
91 // apply template parameters as we find them.
92 while(1) {
93 DeclTy* TmpParam = ParseTemplateParameter();
94 if(!TmpParam) {
95 // If we failed to parse a template parameter, skip until we find
96 // a comma or closing brace.
97 SkipUntil(tok::comma, tok::greater, true, true);
98 }
99
100 // Did we find a comma or the end of the template parmeter list?
101 if(Tok.is(tok::comma)) {
102 ConsumeToken();
103 } else if(Tok.is(tok::greater)) {
104 // Don't consume this... that's done by template parser.
105 break;
106 } else {
107 // Somebody probably forgot to close the template. Skip ahead and
108 // try to get out of the expression. This error is currently
109 // subsumed by whatever goes on in ParseTemplateParameter.
110 // TODO: This could match >>, and it would be nice to avoid those
111 // silly errors with template <vec<T>>.
112 // Diag(Tok.getLocation(), diag::err_expected_comma_greater);
113 SkipUntil(tok::greater, true, true);
114 return false;
115 }
116 }
117 return true;
118}
119
120/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
121///
122/// template-parameter: [C++ temp.param]
123/// type-parameter
124/// parameter-declaration
125///
126/// type-parameter: (see below)
127/// 'class' identifier[opt]
128/// 'class' identifier[opt] '=' type-id
129/// 'typename' identifier[opt]
130/// 'typename' identifier[opt] '=' type-id
131/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
132/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
133Parser::DeclTy *Parser::ParseTemplateParameter() {
134 TryAnnotateCXXScopeToken();
135
136 if(Tok.is(tok::kw_class)
137 || (Tok.is(tok::kw_typename) &&
138 NextToken().isNot(tok::annot_qualtypename))) {
139 return ParseTypeParameter();
140 } else if(Tok.is(tok::kw_template)) {
141 return ParseTemplateTemplateParameter();
142 } else {
143 // If it's none of the above, then it must be a parameter declaration.
144 // NOTE: This will pick up errors in the closure of the template parameter
145 // list (e.g., template < ; Check here to implement >> style closures.
146 return ParseNonTypeTemplateParameter();
147 }
148 return 0;
149}
150
151/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
152/// Other kinds of template parameters are parsed in
153/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
154///
155/// type-parameter: [C++ temp.param]
156/// 'class' identifier[opt]
157/// 'class' identifier[opt] '=' type-id
158/// 'typename' identifier[opt]
159/// 'typename' identifier[opt] '=' type-id
160Parser::DeclTy *Parser::ParseTypeParameter() {
Douglas Gregor26236e82008-12-02 00:41:28 +0000161 assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
162 "A type-parameter starts with 'class' or 'typename'");
163
164 // Consume the 'class' or 'typename' keyword.
165 bool TypenameKeyword = Tok.is(tok::kw_typename);
166 SourceLocation KeyLoc = ConsumeToken();
Douglas Gregoradcac882008-12-01 23:54:00 +0000167
168 // Grab the template parameter name (if given)
Douglas Gregor26236e82008-12-02 00:41:28 +0000169 SourceLocation NameLoc;
170 IdentifierInfo* ParamName = 0;
Douglas Gregoradcac882008-12-01 23:54:00 +0000171 if(Tok.is(tok::identifier)) {
Douglas Gregor26236e82008-12-02 00:41:28 +0000172 ParamName = Tok.getIdentifierInfo();
173 NameLoc = ConsumeToken();
Douglas Gregoradcac882008-12-01 23:54:00 +0000174 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
175 Tok.is(tok::greater)) {
176 // Unnamed template parameter. Don't have to do anything here, just
177 // don't consume this token.
178 } else {
179 Diag(Tok.getLocation(), diag::err_expected_ident);
180 return 0;
181 }
182
Douglas Gregor26236e82008-12-02 00:41:28 +0000183 DeclTy *TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
184 KeyLoc, ParamName, NameLoc);
185
Douglas Gregoradcac882008-12-01 23:54:00 +0000186 // Grab a default type id (if given).
Douglas Gregoradcac882008-12-01 23:54:00 +0000187 if(Tok.is(tok::equal)) {
Douglas Gregor26236e82008-12-02 00:41:28 +0000188 SourceLocation EqualLoc = ConsumeToken();
189 TypeTy *DefaultType = ParseTypeName();
190 if(DefaultType)
191 Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
Douglas Gregoradcac882008-12-01 23:54:00 +0000192 }
193
Douglas Gregor26236e82008-12-02 00:41:28 +0000194 return TypeParam;
Douglas Gregoradcac882008-12-01 23:54:00 +0000195}
196
197/// ParseTemplateTemplateParameter - Handle the parsing of template
198/// template parameters.
199///
200/// type-parameter: [C++ temp.param]
201/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
202/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
203Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {
204 assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
205
206 // Handle the template <...> part.
207 SourceLocation TemplateLoc = ConsumeToken();
208 if(!ParseTemplateParameters(0)) {
209 return 0;
210 }
211
212 // Generate a meaningful error if the user forgot to put class before the
213 // identifier, comma, or greater.
214 if(!Tok.is(tok::kw_class)) {
215 Diag(Tok.getLocation(), diag::err_expected_class_before)
216 << PP.getSpelling(Tok);
217 return 0;
218 }
219 SourceLocation ClassLoc = ConsumeToken();
220
221 // Get the identifier, if given.
222 IdentifierInfo* ident = 0;
223 if(Tok.is(tok::identifier)) {
224 ident = Tok.getIdentifierInfo();
225 ConsumeToken();
226 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
227 // Unnamed template parameter. Don't have to do anything here, just
228 // don't consume this token.
229 } else {
230 Diag(Tok.getLocation(), diag::err_expected_ident);
231 return 0;
232 }
233
234 // Get the a default value, if given.
Sebastian Redl0e9eabc2008-12-09 13:15:23 +0000235 ExprOwner DefaultExpr(Actions);
Douglas Gregoradcac882008-12-01 23:54:00 +0000236 if(Tok.is(tok::equal)) {
237 ConsumeToken();
Sebastian Redl0e9eabc2008-12-09 13:15:23 +0000238 DefaultExpr = ParseCXXIdExpression();
239 if(DefaultExpr.isInvalid()) {
Douglas Gregoradcac882008-12-01 23:54:00 +0000240 return 0;
241 }
242 }
243
244 // FIXME: Add an action for template template parameters.
245 return 0;
246}
247
248/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
249/// template parameters (e.g., in "template<int Size> class array;").
250
251/// template-parameter:
252/// ...
253/// parameter-declaration
254///
255/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
256/// but that didn't work out to well. Instead, this tries to recrate the basic
257/// parsing of parameter declarations, but tries to constrain it for template
258/// parameters.
Douglas Gregor26236e82008-12-02 00:41:28 +0000259/// FIXME: We need to make a ParseParameterDeclaration that works for
260/// non-type template parameters and normal function parameters.
261Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {
262 SourceLocation StartLoc = Tok.getLocation();
Douglas Gregoradcac882008-12-01 23:54:00 +0000263
264 // Parse the declaration-specifiers (i.e., the type).
Douglas Gregor26236e82008-12-02 00:41:28 +0000265 // FIXME: The type should probably be restricted in some way... Not all
Douglas Gregoradcac882008-12-01 23:54:00 +0000266 // declarators (parts of declarators?) are accepted for parameters.
Douglas Gregor26236e82008-12-02 00:41:28 +0000267 DeclSpec DS;
268 ParseDeclarationSpecifiers(DS);
Douglas Gregoradcac882008-12-01 23:54:00 +0000269
270 // Parse this as a typename.
Douglas Gregor26236e82008-12-02 00:41:28 +0000271 Declarator ParamDecl(DS, Declarator::TemplateParamContext);
272 ParseDeclarator(ParamDecl);
273 if(DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
Douglas Gregoradcac882008-12-01 23:54:00 +0000274 // This probably shouldn't happen - and it's more of a Sema thing, but
275 // basically we didn't parse the type name because we couldn't associate
276 // it with an AST node. we should just skip to the comma or greater.
277 // TODO: This is currently a placeholder for some kind of Sema Error.
278 Diag(Tok.getLocation(), diag::err_parse_error);
279 SkipUntil(tok::comma, tok::greater, true, true);
280 return 0;
281 }
282
Douglas Gregor26236e82008-12-02 00:41:28 +0000283 // Create the parameter.
284 DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl);
Douglas Gregoradcac882008-12-01 23:54:00 +0000285
286 // Is there a default value? Parsing this can be fairly annoying because
287 // we have to stop on the first non-nested (paren'd) '>' as the closure
288 // for the template parameter list. Or a ','.
289 if(Tok.is(tok::equal)) {
290 // TODO: Implement default non-type values.
291 SkipUntil(tok::comma, tok::greater, true, true);
292 }
293
Douglas Gregor26236e82008-12-02 00:41:28 +0000294 return Param;
Douglas Gregoradcac882008-12-01 23:54:00 +0000295}