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