blob: 9a7f6cbd738fa2b5487c1261c66320aa31a2ca6a [file] [log] [blame]
Douglas Gregorb3bec712008-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"
18
19using namespace clang;
20
21/// ParseTemplateDeclaration - Parse a template declaration, which includes
22/// the template parameter list and either a function of class declaration.
23///
24/// template-declaration: [C++ temp]
25/// 'export'[opt] 'template' '<' template-parameter-list '>' declaration
26Parser::DeclTy *Parser::ParseTemplateDeclaration(unsigned Context) {
27 assert((Tok.is(tok::kw_export) || Tok.is(tok::kw_template)) &&
28 "Token does not start a template declaration.");
29
30 // Consume the optional export token, if it exists, followed by the
31 // namespace token.
32 bool isExported = false;
33 if(Tok.is(tok::kw_export)) {
34 SourceLocation ExportLoc = ConsumeToken();
35 if(!Tok.is(tok::kw_template)) {
36 Diag(Tok.getLocation(), diag::err_expected_template);
37 return 0;
38 }
39 isExported = true;
40 }
41 SourceLocation TemplateLoc = ConsumeToken();
42
43 // Try to parse the template parameters, and the declaration if successful.
44 if(ParseTemplateParameters(0)) {
45 // For some reason, this is generating a compiler error when parsing the
46 // declaration. Apparently, ParseDeclaration doesn't want to match a
47 // function-definition, but will match a function declaration.
48 // TODO: ParseDeclarationOrFunctionDefinition
49 return ParseDeclaration(Context);
50 }
51 return 0;
52}
53
54/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
55/// angle brackets.
56bool Parser::ParseTemplateParameters(DeclTy* TmpDecl) {
57 // Get the template parameter list.
58 if(!Tok.is(tok::less)) {
59 Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
60 return false;
61 }
62 ConsumeToken();
63
64 // Try to parse the template parameter list.
65 if(ParseTemplateParameterList(0)) {
66 if(!Tok.is(tok::greater)) {
67 Diag(Tok.getLocation(), diag::err_expected_greater);
68 return false;
69 }
70 ConsumeToken();
71 }
72 return true;
73}
74
75/// ParseTemplateParameterList - Parse a template parameter list. If
76/// the parsing fails badly (i.e., closing bracket was left out), this
77/// will try to put the token stream in a reasonable position (closing
78/// a statement, etc.) and return false.
79///
80/// template-parameter-list: [C++ temp]
81/// template-parameter
82/// template-parameter-list ',' template-parameter
83bool Parser::ParseTemplateParameterList(DeclTy* TmpDecl) {
84 // FIXME: For now, this is just going to consume the template parameters.
85 // Eventually, we should pass the template decl AST node as a parameter and
86 // apply template parameters as we find them.
87 while(1) {
88 DeclTy* TmpParam = ParseTemplateParameter();
89 if(!TmpParam) {
90 // If we failed to parse a template parameter, skip until we find
91 // a comma or closing brace.
92 SkipUntil(tok::comma, tok::greater, true, true);
93 }
94
95 // Did we find a comma or the end of the template parmeter list?
96 if(Tok.is(tok::comma)) {
97 ConsumeToken();
98 } else if(Tok.is(tok::greater)) {
99 // Don't consume this... that's done by template parser.
100 break;
101 } else {
102 // Somebody probably forgot to close the template. Skip ahead and
103 // try to get out of the expression. This error is currently
104 // subsumed by whatever goes on in ParseTemplateParameter.
105 // TODO: This could match >>, and it would be nice to avoid those
106 // silly errors with template <vec<T>>.
107 // Diag(Tok.getLocation(), diag::err_expected_comma_greater);
108 SkipUntil(tok::greater, true, true);
109 return false;
110 }
111 }
112 return true;
113}
114
115/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
116///
117/// template-parameter: [C++ temp.param]
118/// type-parameter
119/// parameter-declaration
120///
121/// type-parameter: (see below)
122/// 'class' identifier[opt]
123/// 'class' identifier[opt] '=' type-id
124/// 'typename' identifier[opt]
125/// 'typename' identifier[opt] '=' type-id
126/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
127/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
128Parser::DeclTy *Parser::ParseTemplateParameter() {
129 TryAnnotateCXXScopeToken();
130
131 if(Tok.is(tok::kw_class)
132 || (Tok.is(tok::kw_typename) &&
133 NextToken().isNot(tok::annot_qualtypename))) {
134 return ParseTypeParameter();
135 } else if(Tok.is(tok::kw_template)) {
136 return ParseTemplateTemplateParameter();
137 } else {
138 // If it's none of the above, then it must be a parameter declaration.
139 // NOTE: This will pick up errors in the closure of the template parameter
140 // list (e.g., template < ; Check here to implement >> style closures.
141 return ParseNonTypeTemplateParameter();
142 }
143 return 0;
144}
145
146/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
147/// Other kinds of template parameters are parsed in
148/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
149///
150/// type-parameter: [C++ temp.param]
151/// 'class' identifier[opt]
152/// 'class' identifier[opt] '=' type-id
153/// 'typename' identifier[opt]
154/// 'typename' identifier[opt] '=' type-id
155Parser::DeclTy *Parser::ParseTypeParameter() {
156 SourceLocation keyLoc = ConsumeToken();
157
158 // Grab the template parameter name (if given)
159 IdentifierInfo* paramName = 0;
160 if(Tok.is(tok::identifier)) {
161 paramName = Tok.getIdentifierInfo();
162 ConsumeToken();
163 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
164 Tok.is(tok::greater)) {
165 // Unnamed template parameter. Don't have to do anything here, just
166 // don't consume this token.
167 } else {
168 Diag(Tok.getLocation(), diag::err_expected_ident);
169 return 0;
170 }
171
172 // Grab a default type id (if given).
173 TypeTy* defaultType = 0;
174 if(Tok.is(tok::equal)) {
175 ConsumeToken();
176 defaultType = ParseTypeName();
177 if(!defaultType)
178 return 0;
179 }
180
181 // FIXME: Add an action for type parameters.
182 return 0;
183}
184
185/// ParseTemplateTemplateParameter - Handle the parsing of template
186/// template parameters.
187///
188/// type-parameter: [C++ temp.param]
189/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
190/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
191Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {
192 assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
193
194 // Handle the template <...> part.
195 SourceLocation TemplateLoc = ConsumeToken();
196 if(!ParseTemplateParameters(0)) {
197 return 0;
198 }
199
200 // Generate a meaningful error if the user forgot to put class before the
201 // identifier, comma, or greater.
202 if(!Tok.is(tok::kw_class)) {
203 Diag(Tok.getLocation(), diag::err_expected_class_before)
204 << PP.getSpelling(Tok);
205 return 0;
206 }
207 SourceLocation ClassLoc = ConsumeToken();
208
209 // Get the identifier, if given.
210 IdentifierInfo* ident = 0;
211 if(Tok.is(tok::identifier)) {
212 ident = Tok.getIdentifierInfo();
213 ConsumeToken();
214 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
215 // Unnamed template parameter. Don't have to do anything here, just
216 // don't consume this token.
217 } else {
218 Diag(Tok.getLocation(), diag::err_expected_ident);
219 return 0;
220 }
221
222 // Get the a default value, if given.
223 ExprResult defaultExpr;
224 if(Tok.is(tok::equal)) {
225 ConsumeToken();
226 defaultExpr = ParseCXXIdExpression();
227 if(defaultExpr.isInvalid) {
228 return 0;
229 }
230 }
231
232 // FIXME: Add an action for template template parameters.
233 return 0;
234}
235
236/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
237/// template parameters (e.g., in "template<int Size> class array;").
238
239/// template-parameter:
240/// ...
241/// parameter-declaration
242///
243/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
244/// but that didn't work out to well. Instead, this tries to recrate the basic
245/// parsing of parameter declarations, but tries to constrain it for template
246/// parameters.
247/// FIXME: We need to make ParseParameterDeclaration work for non-type
248/// template parameters, too.
249Parser::DeclTy* Parser::ParseNonTypeTemplateParameter()
250{
251 SourceLocation startLoc = Tok.getLocation();
252
253 // Parse the declaration-specifiers (i.e., the type).
254 // FIXME:: The type should probably be restricted in some way... Not all
255 // declarators (parts of declarators?) are accepted for parameters.
256 DeclSpec ds;
257 ParseDeclarationSpecifiers(ds);
258
259 // Parse this as a typename.
260 Declarator decl(ds, Declarator::TypeNameContext);
261 ParseDeclarator(decl);
262 if(ds.getTypeSpecType() == DeclSpec::TST_unspecified && !ds.getTypeRep()) {
263 // This probably shouldn't happen - and it's more of a Sema thing, but
264 // basically we didn't parse the type name because we couldn't associate
265 // it with an AST node. we should just skip to the comma or greater.
266 // TODO: This is currently a placeholder for some kind of Sema Error.
267 Diag(Tok.getLocation(), diag::err_parse_error);
268 SkipUntil(tok::comma, tok::greater, true, true);
269 return 0;
270 }
271
272 // If there's an identifier after the typename, parse that as part of the
273 // declarator - or something.
274 if(Tok.is(tok::identifier)) {
275 ConsumeToken();
276 }
277
278 // Is there a default value? Parsing this can be fairly annoying because
279 // we have to stop on the first non-nested (paren'd) '>' as the closure
280 // for the template parameter list. Or a ','.
281 if(Tok.is(tok::equal)) {
282 // TODO: Implement default non-type values.
283 SkipUntil(tok::comma, tok::greater, true, true);
284 }
285
286 // FIXME: Add an action for non-type template parameters.
287 return 0;
288}