blob: 9bd35dd11005d867237e32180abe02c4f938c69e [file] [log] [blame]
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +00001//===--- ParseTentative.cpp - Ambiguity Resolution 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 the tentative parsing portions of the Parser
11// interfaces, for ambiguity resolution.
12//
13//===----------------------------------------------------------------------===//
14
15#include "clang/Parse/Parser.h"
16#include "clang/Basic/Diagnostic.h"
17using namespace clang;
18
19/// isCXXDeclarationStatement - C++-specialized function that disambiguates
20/// between a declaration or an expression statement, when parsing function
21/// bodies. Returns true for declaration, false for expression.
22///
23/// declaration-statement:
24/// block-declaration
25///
26/// block-declaration:
27/// simple-declaration
28/// asm-definition
29/// namespace-alias-definition
30/// using-declaration
31/// using-directive
32/// [C++0x] static_assert-declaration [TODO]
33///
34/// asm-definition:
35/// 'asm' '(' string-literal ')' ';'
36///
37/// namespace-alias-definition:
38/// 'namespace' identifier = qualified-namespace-specifier ';'
39///
40/// using-declaration:
41/// 'using' typename[opt] '::'[opt] nested-name-specifier
42/// unqualified-id ';'
43/// 'using' '::' unqualified-id ;
44///
45/// using-directive:
46/// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
47/// namespace-name ';'
48///
49/// [C++0x] static_assert-declaration: [TODO]
50/// [C++0x] static_assert '(' constant-expression ',' string-literal ')' ';'
51///
52bool Parser::isCXXDeclarationStatement() {
53 switch (Tok.getKind()) {
54 // asm-definition
55 case tok::kw_asm:
56 // namespace-alias-definition
57 case tok::kw_namespace:
58 // using-declaration
59 // using-directive
60 case tok::kw_using:
61 return true;
62 default:
63 // simple-declaration
64 return isCXXSimpleDeclaration();
65 }
66}
67
68/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
69/// between a simple-declaration or an expression-statement.
70/// If during the disambiguation process a parsing error is encountered,
71/// the function returns true to let the declaration parsing code handle it.
72/// Returns false if the statement is disambiguated as expression.
73///
74/// simple-declaration:
75/// decl-specifier-seq init-declarator-list[opt] ';'
76///
77bool Parser::isCXXSimpleDeclaration() {
78 // C++ 6.8p1:
79 // There is an ambiguity in the grammar involving expression-statements and
80 // declarations: An expression-statement with a function-style explicit type
81 // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
82 // from a declaration where the first declarator starts with a '('. In those
83 // cases the statement is a declaration. [Note: To disambiguate, the whole
84 // statement might have to be examined to determine if it is an
85 // expression-statement or a declaration].
86
87 // C++ 6.8p3:
88 // The disambiguation is purely syntactic; that is, the meaning of the names
89 // occurring in such a statement, beyond whether they are type-names or not,
90 // is not generally used in or changed by the disambiguation. Class
91 // templates are instantiated as necessary to determine if a qualified name
92 // is a type-name. Disambiguation precedes parsing, and a statement
93 // disambiguated as a declaration may be an ill-formed declaration.
94
95 // We don't have to parse all of the decl-specifier-seq part. There's only
96 // an ambiguity if the first decl-specifier is
97 // simple-type-specifier/typename-specifier followed by a '(', which may
98 // indicate a function-style cast expression.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +000099 // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
100 // a case.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000101
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000102 TPResult TPR = isCXXDeclarationSpecifier();
103 if (TPR != TPResult::Ambiguous())
104 return TPR != TPResult::False(); // Returns true for TPResult::True() or
105 // TPResult::Error().
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000106
107 // FIXME: Add statistics about the number of ambiguous statements encountered
108 // and how they were resolved (number of declarations+number of expressions).
109
110 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
111 // We need tentative parsing...
112
113 TentativeParsingAction PA(*this);
114
115 TPR = TryParseSimpleDeclaration();
116 SourceLocation TentativeParseLoc = Tok.getLocation();
117
118 PA.Revert();
119
120 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000121 if (TPR == TPResult::Error())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000122 return true;
123
124 // Declarations take precedence over expressions.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000125 if (TPR == TPResult::Ambiguous())
126 TPR = TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000127
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000128 assert(TPR == TPResult::True() || TPR == TPResult::False());
129 if (TPR == TPResult::True() && Tok.isNot(tok::kw_void)) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000130 // We have a declaration that looks like a functional cast; there's a high
131 // chance that the author intended the statement to be an expression.
132 // Emit a warning.
133 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
134 "declaration", SourceRange(Tok.getLocation(), TentativeParseLoc));
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000135 } else if (TPR == TPResult::False() && Tok.is(tok::kw_void)) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000136 // A functional cast to 'void' expression ? Warning..
137 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
138 "expression", SourceRange(Tok.getLocation(), TentativeParseLoc));
139 }
140
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000141 return TPR == TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000142}
143
144/// simple-declaration:
145/// decl-specifier-seq init-declarator-list[opt] ';'
146///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000147Parser::TPResult Parser::TryParseSimpleDeclaration() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000148 // We know that we have a simple-type-specifier/typename-specifier followed
149 // by a '('.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000150 assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000151
152 if (Tok.is(tok::kw_typeof))
153 TryParseTypeofSpecifier();
154 else
155 ConsumeToken();
156
157 assert(Tok.is(tok::l_paren) && "Expected '('");
158
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000159 TPResult TPR = TryParseInitDeclaratorList();
160 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000161 return TPR;
162
163 if (Tok.isNot(tok::semi))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000164 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000165
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000166 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000167}
168
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000169/// init-declarator-list:
170/// init-declarator
171/// init-declarator-list ',' init-declarator
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000172///
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000173/// init-declarator:
174/// declarator initializer[opt]
175/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000176///
177/// initializer:
178/// '=' initializer-clause
179/// '(' expression-list ')'
180///
181/// initializer-clause:
182/// assignment-expression
183/// '{' initializer-list ','[opt] '}'
184/// '{' '}'
185///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000186Parser::TPResult Parser::TryParseInitDeclaratorList() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000187 // GCC only examines the first declarator for disambiguation:
188 // i.e:
189 // int(x), ++x; // GCC regards it as ill-formed declaration.
190 //
191 // Comeau and MSVC will regard the above statement as correct expression.
192 // Clang examines all of the declarators and also regards the above statement
193 // as correct expression.
194
195 while (1) {
196 // declarator
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000197 TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
198 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000199 return TPR;
200
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000201 // [GNU] simple-asm-expr[opt] attributes[opt]
202 if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000203 return TPResult::True();
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000204
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000205 // initializer[opt]
206 if (Tok.is(tok::l_paren)) {
207 // Parse through the parens.
208 ConsumeParen();
209 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000210 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000211 } else if (Tok.is(tok::equal)) {
212 // MSVC won't examine the rest of declarators if '=' is encountered, it
213 // will conclude that it is a declaration.
214 // Comeau and Clang will examine the rest of declarators.
215 // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
216 // expression.
217 //
218 // Parse through the initializer-clause.
219 SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
220 }
221
222 if (Tok.isNot(tok::comma))
223 break;
224 ConsumeToken(); // the comma.
225 }
226
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000227 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000228}
229
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000230/// isCXXConditionDeclaration - Disambiguates between a declaration or an
231/// expression for a condition of a if/switch/while/for statement.
232/// If during the disambiguation process a parsing error is encountered,
233/// the function returns true to let the declaration parsing code handle it.
234///
235/// condition:
236/// expression
237/// type-specifier-seq declarator '=' assignment-expression
238/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
239/// '=' assignment-expression
240///
241bool Parser::isCXXConditionDeclaration() {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000242 TPResult TPR = isCXXDeclarationSpecifier();
243 if (TPR != TPResult::Ambiguous())
244 return TPR != TPResult::False(); // Returns true for TPResult::True() or
245 // TPResult::Error().
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000246
247 // FIXME: Add statistics about the number of ambiguous statements encountered
248 // and how they were resolved (number of declarations+number of expressions).
249
250 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
251 // We need tentative parsing...
252
253 TentativeParsingAction PA(*this);
254
255 // type-specifier-seq
256 if (Tok.is(tok::kw_typeof))
257 TryParseTypeofSpecifier();
258 else
259 ConsumeToken();
260 assert(Tok.is(tok::l_paren) && "Expected '('");
261
262 // declarator
263 TPR = TryParseDeclarator(false/*mayBeAbstract*/);
264
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000265 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000266 if (TPR == TPResult::Error())
267 TPR = TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000268
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000269 if (TPR == TPResult::Ambiguous()) {
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000270 // '='
271 // [GNU] simple-asm-expr[opt] attributes[opt]
272 if (Tok.is(tok::equal) ||
273 Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000274 TPR = TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000275 else
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000276 TPR = TPResult::False();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000277 }
278
Argyrios Kyrtzidisca35baa2008-10-05 15:19:49 +0000279 PA.Revert();
280
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000281 assert(TPR == TPResult::True() || TPR == TPResult::False());
282 return TPR == TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000283}
284
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000285/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to
286/// know whether the parens contain an expression or a type-id.
287/// Returns true for a type-id and false for an expression.
288/// If during the disambiguation process a parsing error is encountered,
289/// the function returns true to let the declaration parsing code handle it.
290///
291/// type-id:
292/// type-specifier-seq abstract-declarator[opt]
293///
294bool Parser::isCXXTypeIdInParens() {
295 TPResult TPR = isCXXDeclarationSpecifier();
296 if (TPR != TPResult::Ambiguous())
297 return TPR != TPResult::False(); // Returns true for TPResult::True() or
298 // TPResult::Error().
299
300 // FIXME: Add statistics about the number of ambiguous statements encountered
301 // and how they were resolved (number of declarations+number of expressions).
302
303 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
304 // We need tentative parsing...
305
306 TentativeParsingAction PA(*this);
307
308 // type-specifier-seq
309 if (Tok.is(tok::kw_typeof))
310 TryParseTypeofSpecifier();
311 else
312 ConsumeToken();
313 assert(Tok.is(tok::l_paren) && "Expected '('");
314
315 // declarator
316 TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
317
318 // In case of an error, let the declaration parsing code handle it.
319 if (TPR == TPResult::Error())
320 TPR = TPResult::True();
321
322 if (TPR == TPResult::Ambiguous()) {
323 // We are supposed to be inside parens, so if after the abstract declarator
324 // we encounter a ')' this is a type-id, otherwise it's an expression.
325 if (Tok.is(tok::r_paren))
326 TPR = TPResult::True();
327 else
328 TPR = TPResult::False();
329 }
330
331 PA.Revert();
332
333 assert(TPR == TPResult::True() || TPR == TPResult::False());
334 return TPR == TPResult::True();
335}
336
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000337/// declarator:
338/// direct-declarator
339/// ptr-operator declarator
340///
341/// direct-declarator:
342/// declarator-id
343/// direct-declarator '(' parameter-declaration-clause ')'
344/// cv-qualifier-seq[opt] exception-specification[opt]
345/// direct-declarator '[' constant-expression[opt] ']'
346/// '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000347/// [GNU] '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000348///
349/// abstract-declarator:
350/// ptr-operator abstract-declarator[opt]
351/// direct-abstract-declarator
352///
353/// direct-abstract-declarator:
354/// direct-abstract-declarator[opt]
355/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
356/// exception-specification[opt]
357/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
358/// '(' abstract-declarator ')'
359///
360/// ptr-operator:
361/// '*' cv-qualifier-seq[opt]
362/// '&'
363/// [C++0x] '&&' [TODO]
364/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
365///
366/// cv-qualifier-seq:
367/// cv-qualifier cv-qualifier-seq[opt]
368///
369/// cv-qualifier:
370/// 'const'
371/// 'volatile'
372///
373/// declarator-id:
374/// id-expression
375///
376/// id-expression:
377/// unqualified-id
378/// qualified-id [TODO]
379///
380/// unqualified-id:
381/// identifier
382/// operator-function-id [TODO]
383/// conversion-function-id [TODO]
384/// '~' class-name [TODO]
385/// template-id [TODO]
386///
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000387Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
388 bool mayHaveIdentifier) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000389 // declarator:
390 // direct-declarator
391 // ptr-operator declarator
392
393 while (1) {
394 if (Tok.is(tok::star) || Tok.is(tok::amp)) {
395 // ptr-operator
396 ConsumeToken();
397 while (Tok.is(tok::kw_const) ||
398 Tok.is(tok::kw_volatile) ||
399 Tok.is(tok::kw_restrict) )
400 ConsumeToken();
401 } else {
402 break;
403 }
404 }
405
406 // direct-declarator:
407 // direct-abstract-declarator:
408
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000409 if (Tok.is(tok::identifier) && mayHaveIdentifier) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000410 // declarator-id
411 ConsumeToken();
412 } else if (Tok.is(tok::l_paren)) {
413 if (mayBeAbstract && isCXXFunctionDeclarator()) {
414 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
415 // exception-specification[opt]
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000416 TPResult TPR = TryParseFunctionDeclarator();
417 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000418 return TPR;
419 } else {
420 // '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000421 // '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000422 // '(' abstract-declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000423 ConsumeParen();
424 if (Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000425 return TPResult::True(); // attributes indicate declaration
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000426 TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000427 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000428 return TPR;
429 if (Tok.isNot(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000430 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000431 ConsumeParen();
432 }
433 } else if (!mayBeAbstract) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000434 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000435 }
436
437 while (1) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000438 TPResult TPR(TPResult::Ambiguous());
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000439
440 if (Tok.is(tok::l_paren)) {
441 // direct-declarator '(' parameter-declaration-clause ')'
442 // cv-qualifier-seq[opt] exception-specification[opt]
443 if (!isCXXFunctionDeclarator())
444 break;
445 TPR = TryParseFunctionDeclarator();
446 } else if (Tok.is(tok::l_square)) {
447 // direct-declarator '[' constant-expression[opt] ']'
448 // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
449 TPR = TryParseBracketDeclarator();
450 } else {
451 break;
452 }
453
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000454 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000455 return TPR;
456 }
457
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000458 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000459}
460
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000461/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
462/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
463/// be either a decl-specifier or a function-style cast, and TPResult::Error()
464/// if a parsing error was found and reported.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000465///
466/// decl-specifier:
467/// storage-class-specifier
468/// type-specifier
469/// function-specifier
470/// 'friend'
471/// 'typedef'
472/// [GNU] attributes declaration-specifiers[opt]
473///
474/// storage-class-specifier:
475/// 'register'
476/// 'static'
477/// 'extern'
478/// 'mutable'
479/// 'auto'
480/// [GNU] '__thread'
481///
482/// function-specifier:
483/// 'inline'
484/// 'virtual'
485/// 'explicit'
486///
487/// typedef-name:
488/// identifier
489///
490/// type-specifier:
491/// simple-type-specifier
492/// class-specifier
493/// enum-specifier
494/// elaborated-type-specifier
495/// typename-specifier [TODO]
496/// cv-qualifier
497///
498/// simple-type-specifier:
499/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
500/// '::'[opt] nested-name-specifier 'template'
501/// simple-template-id [TODO]
502/// 'char'
503/// 'wchar_t'
504/// 'bool'
505/// 'short'
506/// 'int'
507/// 'long'
508/// 'signed'
509/// 'unsigned'
510/// 'float'
511/// 'double'
512/// 'void'
513/// [GNU] typeof-specifier
514/// [GNU] '_Complex'
515/// [C++0x] 'auto' [TODO]
516///
517/// type-name:
518/// class-name
519/// enum-name
520/// typedef-name
521///
522/// elaborated-type-specifier:
523/// class-key '::'[opt] nested-name-specifier[opt] identifier
524/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
525/// simple-template-id
526/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
527///
528/// enum-name:
529/// identifier
530///
531/// enum-specifier:
532/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
533/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
534///
535/// class-specifier:
536/// class-head '{' member-specification[opt] '}'
537///
538/// class-head:
539/// class-key identifier[opt] base-clause[opt]
540/// class-key nested-name-specifier identifier base-clause[opt]
541/// class-key nested-name-specifier[opt] simple-template-id
542/// base-clause[opt]
543///
544/// class-key:
545/// 'class'
546/// 'struct'
547/// 'union'
548///
549/// cv-qualifier:
550/// 'const'
551/// 'volatile'
552/// [GNU] restrict
553///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000554Parser::TPResult Parser::isCXXDeclarationSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000555 switch (Tok.getKind()) {
556 // decl-specifier:
557 // storage-class-specifier
558 // type-specifier
559 // function-specifier
560 // 'friend'
561 // 'typedef'
562
563 case tok::kw_friend:
564 case tok::kw_typedef:
565 // storage-class-specifier
566 case tok::kw_register:
567 case tok::kw_static:
568 case tok::kw_extern:
569 case tok::kw_mutable:
570 case tok::kw_auto:
571 case tok::kw___thread:
572 // function-specifier
573 case tok::kw_inline:
574 case tok::kw_virtual:
575 case tok::kw_explicit:
576
577 // type-specifier:
578 // simple-type-specifier
579 // class-specifier
580 // enum-specifier
581 // elaborated-type-specifier
582 // typename-specifier
583 // cv-qualifier
584
585 // class-specifier
586 // elaborated-type-specifier
587 case tok::kw_class:
588 case tok::kw_struct:
589 case tok::kw_union:
590 // enum-specifier
591 case tok::kw_enum:
592 // cv-qualifier
593 case tok::kw_const:
594 case tok::kw_volatile:
595
596 // GNU
597 case tok::kw_restrict:
598 case tok::kw__Complex:
599 case tok::kw___attribute:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000600 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000601
602 // The ambiguity resides in a simple-type-specifier/typename-specifier
603 // followed by a '('. The '(' could either be the start of:
604 //
605 // direct-declarator:
606 // '(' declarator ')'
607 //
608 // direct-abstract-declarator:
609 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
610 // exception-specification[opt]
611 // '(' abstract-declarator ')'
612 //
613 // or part of a function-style cast expression:
614 //
615 // simple-type-specifier '(' expression-list[opt] ')'
616 //
617
618 // simple-type-specifier:
619
620 case tok::identifier:
621 if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000622 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000623 // FALL THROUGH.
624
625 case tok::kw_char:
626 case tok::kw_wchar_t:
627 case tok::kw_bool:
628 case tok::kw_short:
629 case tok::kw_int:
630 case tok::kw_long:
631 case tok::kw_signed:
632 case tok::kw_unsigned:
633 case tok::kw_float:
634 case tok::kw_double:
635 case tok::kw_void:
636 if (NextToken().is(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000637 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000638
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000639 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000640
641 // GNU typeof support.
642 case tok::kw_typeof: {
643 if (NextToken().isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000644 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000645
646 TentativeParsingAction PA(*this);
647
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000648 TPResult TPR = TryParseTypeofSpecifier();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000649 bool isFollowedByParen = Tok.is(tok::l_paren);
650
651 PA.Revert();
652
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000653 if (TPR == TPResult::Error())
654 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000655
656 if (isFollowedByParen)
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000657 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000658
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000659 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000660 }
661
662 default:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000663 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000664 }
665}
666
667/// [GNU] typeof-specifier:
668/// 'typeof' '(' expressions ')'
669/// 'typeof' '(' type-name ')'
670///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000671Parser::TPResult Parser::TryParseTypeofSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000672 assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
673 ConsumeToken();
674
675 assert(Tok.is(tok::l_paren) && "Expected '('");
676 // Parse through the parens after 'typeof'.
677 ConsumeParen();
678 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000679 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000680
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000681 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000682}
683
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000684Parser::TPResult Parser::TryParseDeclarationSpecifier() {
685 TPResult TPR = isCXXDeclarationSpecifier();
686 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000687 return TPR;
688
689 if (Tok.is(tok::kw_typeof))
690 TryParseTypeofSpecifier();
691 else
692 ConsumeToken();
693
694 assert(Tok.is(tok::l_paren) && "Expected '('!");
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000695 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000696}
697
698/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
699/// a constructor-style initializer, when parsing declaration statements.
700/// Returns true for function declarator and false for constructor-style
701/// initializer.
702/// If during the disambiguation process a parsing error is encountered,
703/// the function returns true to let the declaration parsing code handle it.
704///
705/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
706/// exception-specification[opt]
707///
708bool Parser::isCXXFunctionDeclarator() {
709 TentativeParsingAction PA(*this);
710
711 ConsumeParen();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000712 TPResult TPR = TryParseParameterDeclarationClause();
713 if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
714 TPR = TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000715
716 PA.Revert();
717
718 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000719 if (TPR == TPResult::Error())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000720 return true;
721
722 // Function declarator has precedence over constructor-style initializer.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000723 if (TPR == TPResult::Ambiguous())
724 return true;
725
726 return TPR == TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000727}
728
729/// parameter-declaration-clause:
730/// parameter-declaration-list[opt] '...'[opt]
731/// parameter-declaration-list ',' '...'
732///
733/// parameter-declaration-list:
734/// parameter-declaration
735/// parameter-declaration-list ',' parameter-declaration
736///
737/// parameter-declaration:
738/// decl-specifier-seq declarator
739/// decl-specifier-seq declarator '=' assignment-expression
740/// decl-specifier-seq abstract-declarator[opt]
741/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
742///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000743Parser::TPResult Parser::TryParseParameterDeclarationClause() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000744
745 if (Tok.is(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000746 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000747
748 // parameter-declaration-list[opt] '...'[opt]
749 // parameter-declaration-list ',' '...'
750 //
751 // parameter-declaration-list:
752 // parameter-declaration
753 // parameter-declaration-list ',' parameter-declaration
754 //
755 while (1) {
756 // '...'[opt]
757 if (Tok.is(tok::ellipsis)) {
758 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000759 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000760 }
761
762 // decl-specifier-seq
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000763 TPResult TPR = TryParseDeclarationSpecifier();
764 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000765 return TPR;
766
767 // declarator
768 // abstract-declarator[opt]
769 TPR = TryParseDeclarator(true/*mayBeAbstract*/);
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000770 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000771 return TPR;
772
773 if (Tok.is(tok::equal)) {
774 // '=' assignment-expression
775 // Parse through assignment-expression.
776 tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
777 if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000778 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000779 }
780
781 if (Tok.is(tok::ellipsis)) {
782 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000783 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000784 }
785
786 if (Tok.isNot(tok::comma))
787 break;
788 ConsumeToken(); // the comma.
789 }
790
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000791 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000792}
793
794/// TryParseFunctionDeclarator - We previously determined (using
795/// isCXXFunctionDeclarator) that we are at a function declarator. Now parse
796/// through it.
797///
798/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
799/// exception-specification[opt]
800///
801/// exception-specification:
802/// 'throw' '(' type-id-list[opt] ')'
803///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000804Parser::TPResult Parser::TryParseFunctionDeclarator() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000805 assert(Tok.is(tok::l_paren));
806 // Parse through the parens.
807 ConsumeParen();
808 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000809 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000810
811 // cv-qualifier-seq
812 while (Tok.is(tok::kw_const) ||
813 Tok.is(tok::kw_volatile) ||
814 Tok.is(tok::kw_restrict) )
815 ConsumeToken();
816
817 // exception-specification
818 if (Tok.is(tok::kw_throw)) {
819 ConsumeToken();
820 if (Tok.isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000821 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000822
823 // Parse through the parens after 'throw'.
824 ConsumeParen();
825 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000826 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000827 }
828
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000829 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000830}
831
832/// '[' constant-expression[opt] ']'
833///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000834Parser::TPResult Parser::TryParseBracketDeclarator() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000835 ConsumeBracket();
836 if (!SkipUntil(tok::r_square))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000837 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000838
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000839 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000840}