blob: 5801f9ecb77612af7588677fe0796b298e6caddd [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"
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
Douglas Gregor26236e82008-12-02 00:41:28 +000043 // Enter template-parameter scope.
Douglas Gregor72c3f312008-12-05 18:15:24 +000044 EnterScope(Scope::TemplateParamScope);
Douglas Gregor26236e82008-12-02 00:41:28 +000045
46 // Try to parse the template parameters, and the declaration if
47 // successful.
48 DeclTy *TemplateDecl = 0;
49 if(ParseTemplateParameters(0))
50 TemplateDecl = ParseDeclarationOrFunctionDefinition();
51
52 // Leave template-parameter scope.
53 ExitScope();
54
55 return TemplateDecl;
Douglas Gregoradcac882008-12-01 23:54:00 +000056}
57
58/// ParseTemplateParameters - Parses a template-parameter-list enclosed in
59/// angle brackets.
60bool Parser::ParseTemplateParameters(DeclTy* TmpDecl) {
61 // Get the template parameter list.
62 if(!Tok.is(tok::less)) {
63 Diag(Tok.getLocation(), diag::err_expected_less_after) << "template";
64 return false;
65 }
66 ConsumeToken();
67
68 // Try to parse the template parameter list.
69 if(ParseTemplateParameterList(0)) {
70 if(!Tok.is(tok::greater)) {
71 Diag(Tok.getLocation(), diag::err_expected_greater);
72 return false;
73 }
74 ConsumeToken();
75 }
76 return true;
77}
78
79/// ParseTemplateParameterList - Parse a template parameter list. If
80/// the parsing fails badly (i.e., closing bracket was left out), this
81/// will try to put the token stream in a reasonable position (closing
82/// a statement, etc.) and return false.
83///
84/// template-parameter-list: [C++ temp]
85/// template-parameter
86/// template-parameter-list ',' template-parameter
87bool Parser::ParseTemplateParameterList(DeclTy* TmpDecl) {
88 // FIXME: For now, this is just going to consume the template parameters.
89 // Eventually, we should pass the template decl AST node as a parameter and
90 // apply template parameters as we find them.
91 while(1) {
92 DeclTy* TmpParam = ParseTemplateParameter();
93 if(!TmpParam) {
94 // If we failed to parse a template parameter, skip until we find
95 // a comma or closing brace.
96 SkipUntil(tok::comma, tok::greater, true, true);
97 }
98
99 // Did we find a comma or the end of the template parmeter list?
100 if(Tok.is(tok::comma)) {
101 ConsumeToken();
102 } else if(Tok.is(tok::greater)) {
103 // Don't consume this... that's done by template parser.
104 break;
105 } else {
106 // Somebody probably forgot to close the template. Skip ahead and
107 // try to get out of the expression. This error is currently
108 // subsumed by whatever goes on in ParseTemplateParameter.
109 // TODO: This could match >>, and it would be nice to avoid those
110 // silly errors with template <vec<T>>.
111 // Diag(Tok.getLocation(), diag::err_expected_comma_greater);
112 SkipUntil(tok::greater, true, true);
113 return false;
114 }
115 }
116 return true;
117}
118
119/// ParseTemplateParameter - Parse a template-parameter (C++ [temp.param]).
120///
121/// template-parameter: [C++ temp.param]
122/// type-parameter
123/// parameter-declaration
124///
125/// type-parameter: (see below)
126/// 'class' identifier[opt]
127/// 'class' identifier[opt] '=' type-id
128/// 'typename' identifier[opt]
129/// 'typename' identifier[opt] '=' type-id
130/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
131/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
132Parser::DeclTy *Parser::ParseTemplateParameter() {
133 TryAnnotateCXXScopeToken();
134
135 if(Tok.is(tok::kw_class)
136 || (Tok.is(tok::kw_typename) &&
137 NextToken().isNot(tok::annot_qualtypename))) {
138 return ParseTypeParameter();
139 } else if(Tok.is(tok::kw_template)) {
140 return ParseTemplateTemplateParameter();
141 } else {
142 // If it's none of the above, then it must be a parameter declaration.
143 // NOTE: This will pick up errors in the closure of the template parameter
144 // list (e.g., template < ; Check here to implement >> style closures.
145 return ParseNonTypeTemplateParameter();
146 }
147 return 0;
148}
149
150/// ParseTypeParameter - Parse a template type parameter (C++ [temp.param]).
151/// Other kinds of template parameters are parsed in
152/// ParseTemplateTemplateParameter and ParseNonTypeTemplateParameter.
153///
154/// type-parameter: [C++ temp.param]
155/// 'class' identifier[opt]
156/// 'class' identifier[opt] '=' type-id
157/// 'typename' identifier[opt]
158/// 'typename' identifier[opt] '=' type-id
159Parser::DeclTy *Parser::ParseTypeParameter() {
Douglas Gregor26236e82008-12-02 00:41:28 +0000160 assert((Tok.is(tok::kw_class) || Tok.is(tok::kw_typename)) &&
161 "A type-parameter starts with 'class' or 'typename'");
162
163 // Consume the 'class' or 'typename' keyword.
164 bool TypenameKeyword = Tok.is(tok::kw_typename);
165 SourceLocation KeyLoc = ConsumeToken();
Douglas Gregoradcac882008-12-01 23:54:00 +0000166
167 // Grab the template parameter name (if given)
Douglas Gregor26236e82008-12-02 00:41:28 +0000168 SourceLocation NameLoc;
169 IdentifierInfo* ParamName = 0;
Douglas Gregoradcac882008-12-01 23:54:00 +0000170 if(Tok.is(tok::identifier)) {
Douglas Gregor26236e82008-12-02 00:41:28 +0000171 ParamName = Tok.getIdentifierInfo();
172 NameLoc = ConsumeToken();
Douglas Gregoradcac882008-12-01 23:54:00 +0000173 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) ||
174 Tok.is(tok::greater)) {
175 // Unnamed template parameter. Don't have to do anything here, just
176 // don't consume this token.
177 } else {
178 Diag(Tok.getLocation(), diag::err_expected_ident);
179 return 0;
180 }
181
Douglas Gregor26236e82008-12-02 00:41:28 +0000182 DeclTy *TypeParam = Actions.ActOnTypeParameter(CurScope, TypenameKeyword,
183 KeyLoc, ParamName, NameLoc);
184
Douglas Gregoradcac882008-12-01 23:54:00 +0000185 // Grab a default type id (if given).
Douglas Gregoradcac882008-12-01 23:54:00 +0000186 if(Tok.is(tok::equal)) {
Douglas Gregor26236e82008-12-02 00:41:28 +0000187 SourceLocation EqualLoc = ConsumeToken();
188 TypeTy *DefaultType = ParseTypeName();
189 if(DefaultType)
190 Actions.ActOnTypeParameterDefault(TypeParam, DefaultType);
Douglas Gregoradcac882008-12-01 23:54:00 +0000191 }
192
Douglas Gregor26236e82008-12-02 00:41:28 +0000193 return TypeParam;
Douglas Gregoradcac882008-12-01 23:54:00 +0000194}
195
196/// ParseTemplateTemplateParameter - Handle the parsing of template
197/// template parameters.
198///
199/// type-parameter: [C++ temp.param]
200/// 'template' '<' template-parameter-list '>' 'class' identifier[opt]
201/// 'template' '<' template-parameter-list '>' 'class' identifier[opt] = id-expression
202Parser::DeclTy* Parser::ParseTemplateTemplateParameter() {
203 assert(Tok.is(tok::kw_template) && "Expected 'template' keyword");
204
205 // Handle the template <...> part.
206 SourceLocation TemplateLoc = ConsumeToken();
207 if(!ParseTemplateParameters(0)) {
208 return 0;
209 }
210
211 // Generate a meaningful error if the user forgot to put class before the
212 // identifier, comma, or greater.
213 if(!Tok.is(tok::kw_class)) {
214 Diag(Tok.getLocation(), diag::err_expected_class_before)
215 << PP.getSpelling(Tok);
216 return 0;
217 }
218 SourceLocation ClassLoc = ConsumeToken();
219
220 // Get the identifier, if given.
221 IdentifierInfo* ident = 0;
222 if(Tok.is(tok::identifier)) {
223 ident = Tok.getIdentifierInfo();
224 ConsumeToken();
225 } else if(Tok.is(tok::equal) || Tok.is(tok::comma) || Tok.is(tok::greater)) {
226 // Unnamed template parameter. Don't have to do anything here, just
227 // don't consume this token.
228 } else {
229 Diag(Tok.getLocation(), diag::err_expected_ident);
230 return 0;
231 }
232
233 // Get the a default value, if given.
234 ExprResult defaultExpr;
235 if(Tok.is(tok::equal)) {
236 ConsumeToken();
237 defaultExpr = ParseCXXIdExpression();
238 if(defaultExpr.isInvalid) {
239 return 0;
240 }
241 }
242
243 // FIXME: Add an action for template template parameters.
244 return 0;
245}
246
247/// ParseNonTypeTemplateParameter - Handle the parsing of non-type
248/// template parameters (e.g., in "template<int Size> class array;").
249
250/// template-parameter:
251/// ...
252/// parameter-declaration
253///
254/// NOTE: It would be ideal to simply call out to ParseParameterDeclaration(),
255/// but that didn't work out to well. Instead, this tries to recrate the basic
256/// parsing of parameter declarations, but tries to constrain it for template
257/// parameters.
Douglas Gregor26236e82008-12-02 00:41:28 +0000258/// FIXME: We need to make a ParseParameterDeclaration that works for
259/// non-type template parameters and normal function parameters.
260Parser::DeclTy* Parser::ParseNonTypeTemplateParameter() {
261 SourceLocation StartLoc = Tok.getLocation();
Douglas Gregoradcac882008-12-01 23:54:00 +0000262
263 // Parse the declaration-specifiers (i.e., the type).
Douglas Gregor26236e82008-12-02 00:41:28 +0000264 // FIXME: The type should probably be restricted in some way... Not all
Douglas Gregoradcac882008-12-01 23:54:00 +0000265 // declarators (parts of declarators?) are accepted for parameters.
Douglas Gregor26236e82008-12-02 00:41:28 +0000266 DeclSpec DS;
267 ParseDeclarationSpecifiers(DS);
Douglas Gregoradcac882008-12-01 23:54:00 +0000268
269 // Parse this as a typename.
Douglas Gregor26236e82008-12-02 00:41:28 +0000270 Declarator ParamDecl(DS, Declarator::TemplateParamContext);
271 ParseDeclarator(ParamDecl);
272 if(DS.getTypeSpecType() == DeclSpec::TST_unspecified && !DS.getTypeRep()) {
Douglas Gregoradcac882008-12-01 23:54:00 +0000273 // This probably shouldn't happen - and it's more of a Sema thing, but
274 // basically we didn't parse the type name because we couldn't associate
275 // it with an AST node. we should just skip to the comma or greater.
276 // TODO: This is currently a placeholder for some kind of Sema Error.
277 Diag(Tok.getLocation(), diag::err_parse_error);
278 SkipUntil(tok::comma, tok::greater, true, true);
279 return 0;
280 }
281
Douglas Gregor26236e82008-12-02 00:41:28 +0000282 // Create the parameter.
283 DeclTy *Param = Actions.ActOnNonTypeTemplateParameter(CurScope, ParamDecl);
Douglas Gregoradcac882008-12-01 23:54:00 +0000284
285 // Is there a default value? Parsing this can be fairly annoying because
286 // we have to stop on the first non-nested (paren'd) '>' as the closure
287 // for the template parameter list. Or a ','.
288 if(Tok.is(tok::equal)) {
289 // TODO: Implement default non-type values.
290 SkipUntil(tok::comma, tok::greater, true, true);
291 }
292
Douglas Gregor26236e82008-12-02 00:41:28 +0000293 return Param;
Douglas Gregoradcac882008-12-01 23:54:00 +0000294}