blob: 2f1130ad742caa2ac7372691283f80bffaf2aa6a [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 Kyrtzidis5404a152008-10-05 00:06:24 +0000285/// declarator:
286/// direct-declarator
287/// ptr-operator declarator
288///
289/// direct-declarator:
290/// declarator-id
291/// direct-declarator '(' parameter-declaration-clause ')'
292/// cv-qualifier-seq[opt] exception-specification[opt]
293/// direct-declarator '[' constant-expression[opt] ']'
294/// '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000295/// [GNU] '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000296///
297/// abstract-declarator:
298/// ptr-operator abstract-declarator[opt]
299/// direct-abstract-declarator
300///
301/// direct-abstract-declarator:
302/// direct-abstract-declarator[opt]
303/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
304/// exception-specification[opt]
305/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
306/// '(' abstract-declarator ')'
307///
308/// ptr-operator:
309/// '*' cv-qualifier-seq[opt]
310/// '&'
311/// [C++0x] '&&' [TODO]
312/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
313///
314/// cv-qualifier-seq:
315/// cv-qualifier cv-qualifier-seq[opt]
316///
317/// cv-qualifier:
318/// 'const'
319/// 'volatile'
320///
321/// declarator-id:
322/// id-expression
323///
324/// id-expression:
325/// unqualified-id
326/// qualified-id [TODO]
327///
328/// unqualified-id:
329/// identifier
330/// operator-function-id [TODO]
331/// conversion-function-id [TODO]
332/// '~' class-name [TODO]
333/// template-id [TODO]
334///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000335Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000336 // declarator:
337 // direct-declarator
338 // ptr-operator declarator
339
340 while (1) {
341 if (Tok.is(tok::star) || Tok.is(tok::amp)) {
342 // ptr-operator
343 ConsumeToken();
344 while (Tok.is(tok::kw_const) ||
345 Tok.is(tok::kw_volatile) ||
346 Tok.is(tok::kw_restrict) )
347 ConsumeToken();
348 } else {
349 break;
350 }
351 }
352
353 // direct-declarator:
354 // direct-abstract-declarator:
355
356 if (Tok.is(tok::identifier)) {
357 // declarator-id
358 ConsumeToken();
359 } else if (Tok.is(tok::l_paren)) {
360 if (mayBeAbstract && isCXXFunctionDeclarator()) {
361 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
362 // exception-specification[opt]
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000363 TPResult TPR = TryParseFunctionDeclarator();
364 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000365 return TPR;
366 } else {
367 // '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000368 // '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000369 // '(' abstract-declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000370 ConsumeParen();
371 if (Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000372 return TPResult::True(); // attributes indicate declaration
373 TPResult TPR = TryParseDeclarator(mayBeAbstract);
374 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000375 return TPR;
376 if (Tok.isNot(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000377 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000378 ConsumeParen();
379 }
380 } else if (!mayBeAbstract) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000381 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000382 }
383
384 while (1) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000385 TPResult TPR(TPResult::Ambiguous());
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000386
387 if (Tok.is(tok::l_paren)) {
388 // direct-declarator '(' parameter-declaration-clause ')'
389 // cv-qualifier-seq[opt] exception-specification[opt]
390 if (!isCXXFunctionDeclarator())
391 break;
392 TPR = TryParseFunctionDeclarator();
393 } else if (Tok.is(tok::l_square)) {
394 // direct-declarator '[' constant-expression[opt] ']'
395 // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
396 TPR = TryParseBracketDeclarator();
397 } else {
398 break;
399 }
400
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000401 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000402 return TPR;
403 }
404
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000405 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000406}
407
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000408/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
409/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
410/// be either a decl-specifier or a function-style cast, and TPResult::Error()
411/// if a parsing error was found and reported.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000412///
413/// decl-specifier:
414/// storage-class-specifier
415/// type-specifier
416/// function-specifier
417/// 'friend'
418/// 'typedef'
419/// [GNU] attributes declaration-specifiers[opt]
420///
421/// storage-class-specifier:
422/// 'register'
423/// 'static'
424/// 'extern'
425/// 'mutable'
426/// 'auto'
427/// [GNU] '__thread'
428///
429/// function-specifier:
430/// 'inline'
431/// 'virtual'
432/// 'explicit'
433///
434/// typedef-name:
435/// identifier
436///
437/// type-specifier:
438/// simple-type-specifier
439/// class-specifier
440/// enum-specifier
441/// elaborated-type-specifier
442/// typename-specifier [TODO]
443/// cv-qualifier
444///
445/// simple-type-specifier:
446/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
447/// '::'[opt] nested-name-specifier 'template'
448/// simple-template-id [TODO]
449/// 'char'
450/// 'wchar_t'
451/// 'bool'
452/// 'short'
453/// 'int'
454/// 'long'
455/// 'signed'
456/// 'unsigned'
457/// 'float'
458/// 'double'
459/// 'void'
460/// [GNU] typeof-specifier
461/// [GNU] '_Complex'
462/// [C++0x] 'auto' [TODO]
463///
464/// type-name:
465/// class-name
466/// enum-name
467/// typedef-name
468///
469/// elaborated-type-specifier:
470/// class-key '::'[opt] nested-name-specifier[opt] identifier
471/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
472/// simple-template-id
473/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
474///
475/// enum-name:
476/// identifier
477///
478/// enum-specifier:
479/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
480/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
481///
482/// class-specifier:
483/// class-head '{' member-specification[opt] '}'
484///
485/// class-head:
486/// class-key identifier[opt] base-clause[opt]
487/// class-key nested-name-specifier identifier base-clause[opt]
488/// class-key nested-name-specifier[opt] simple-template-id
489/// base-clause[opt]
490///
491/// class-key:
492/// 'class'
493/// 'struct'
494/// 'union'
495///
496/// cv-qualifier:
497/// 'const'
498/// 'volatile'
499/// [GNU] restrict
500///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000501Parser::TPResult Parser::isCXXDeclarationSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000502 switch (Tok.getKind()) {
503 // decl-specifier:
504 // storage-class-specifier
505 // type-specifier
506 // function-specifier
507 // 'friend'
508 // 'typedef'
509
510 case tok::kw_friend:
511 case tok::kw_typedef:
512 // storage-class-specifier
513 case tok::kw_register:
514 case tok::kw_static:
515 case tok::kw_extern:
516 case tok::kw_mutable:
517 case tok::kw_auto:
518 case tok::kw___thread:
519 // function-specifier
520 case tok::kw_inline:
521 case tok::kw_virtual:
522 case tok::kw_explicit:
523
524 // type-specifier:
525 // simple-type-specifier
526 // class-specifier
527 // enum-specifier
528 // elaborated-type-specifier
529 // typename-specifier
530 // cv-qualifier
531
532 // class-specifier
533 // elaborated-type-specifier
534 case tok::kw_class:
535 case tok::kw_struct:
536 case tok::kw_union:
537 // enum-specifier
538 case tok::kw_enum:
539 // cv-qualifier
540 case tok::kw_const:
541 case tok::kw_volatile:
542
543 // GNU
544 case tok::kw_restrict:
545 case tok::kw__Complex:
546 case tok::kw___attribute:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000547 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000548
549 // The ambiguity resides in a simple-type-specifier/typename-specifier
550 // followed by a '('. The '(' could either be the start of:
551 //
552 // direct-declarator:
553 // '(' declarator ')'
554 //
555 // direct-abstract-declarator:
556 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
557 // exception-specification[opt]
558 // '(' abstract-declarator ')'
559 //
560 // or part of a function-style cast expression:
561 //
562 // simple-type-specifier '(' expression-list[opt] ')'
563 //
564
565 // simple-type-specifier:
566
567 case tok::identifier:
568 if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000569 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000570 // FALL THROUGH.
571
572 case tok::kw_char:
573 case tok::kw_wchar_t:
574 case tok::kw_bool:
575 case tok::kw_short:
576 case tok::kw_int:
577 case tok::kw_long:
578 case tok::kw_signed:
579 case tok::kw_unsigned:
580 case tok::kw_float:
581 case tok::kw_double:
582 case tok::kw_void:
583 if (NextToken().is(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000584 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000585
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000586 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000587
588 // GNU typeof support.
589 case tok::kw_typeof: {
590 if (NextToken().isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000591 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000592
593 TentativeParsingAction PA(*this);
594
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000595 TPResult TPR = TryParseTypeofSpecifier();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000596 bool isFollowedByParen = Tok.is(tok::l_paren);
597
598 PA.Revert();
599
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000600 if (TPR == TPResult::Error())
601 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000602
603 if (isFollowedByParen)
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000604 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000605
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000606 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000607 }
608
609 default:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000610 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000611 }
612}
613
614/// [GNU] typeof-specifier:
615/// 'typeof' '(' expressions ')'
616/// 'typeof' '(' type-name ')'
617///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000618Parser::TPResult Parser::TryParseTypeofSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000619 assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
620 ConsumeToken();
621
622 assert(Tok.is(tok::l_paren) && "Expected '('");
623 // Parse through the parens after 'typeof'.
624 ConsumeParen();
625 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000626 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000627
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000628 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000629}
630
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000631Parser::TPResult Parser::TryParseDeclarationSpecifier() {
632 TPResult TPR = isCXXDeclarationSpecifier();
633 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000634 return TPR;
635
636 if (Tok.is(tok::kw_typeof))
637 TryParseTypeofSpecifier();
638 else
639 ConsumeToken();
640
641 assert(Tok.is(tok::l_paren) && "Expected '('!");
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000642 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000643}
644
645/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
646/// a constructor-style initializer, when parsing declaration statements.
647/// Returns true for function declarator and false for constructor-style
648/// initializer.
649/// If during the disambiguation process a parsing error is encountered,
650/// the function returns true to let the declaration parsing code handle it.
651///
652/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
653/// exception-specification[opt]
654///
655bool Parser::isCXXFunctionDeclarator() {
656 TentativeParsingAction PA(*this);
657
658 ConsumeParen();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000659 TPResult TPR = TryParseParameterDeclarationClause();
660 if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
661 TPR = TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000662
663 PA.Revert();
664
665 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000666 if (TPR == TPResult::Error())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000667 return true;
668
669 // Function declarator has precedence over constructor-style initializer.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000670 if (TPR == TPResult::Ambiguous())
671 return true;
672
673 return TPR == TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000674}
675
676/// parameter-declaration-clause:
677/// parameter-declaration-list[opt] '...'[opt]
678/// parameter-declaration-list ',' '...'
679///
680/// parameter-declaration-list:
681/// parameter-declaration
682/// parameter-declaration-list ',' parameter-declaration
683///
684/// parameter-declaration:
685/// decl-specifier-seq declarator
686/// decl-specifier-seq declarator '=' assignment-expression
687/// decl-specifier-seq abstract-declarator[opt]
688/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
689///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000690Parser::TPResult Parser::TryParseParameterDeclarationClause() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000691
692 if (Tok.is(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000693 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000694
695 // parameter-declaration-list[opt] '...'[opt]
696 // parameter-declaration-list ',' '...'
697 //
698 // parameter-declaration-list:
699 // parameter-declaration
700 // parameter-declaration-list ',' parameter-declaration
701 //
702 while (1) {
703 // '...'[opt]
704 if (Tok.is(tok::ellipsis)) {
705 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000706 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000707 }
708
709 // decl-specifier-seq
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000710 TPResult TPR = TryParseDeclarationSpecifier();
711 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000712 return TPR;
713
714 // declarator
715 // abstract-declarator[opt]
716 TPR = TryParseDeclarator(true/*mayBeAbstract*/);
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000717 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000718 return TPR;
719
720 if (Tok.is(tok::equal)) {
721 // '=' assignment-expression
722 // Parse through assignment-expression.
723 tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
724 if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000725 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000726 }
727
728 if (Tok.is(tok::ellipsis)) {
729 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000730 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000731 }
732
733 if (Tok.isNot(tok::comma))
734 break;
735 ConsumeToken(); // the comma.
736 }
737
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000738 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000739}
740
741/// TryParseFunctionDeclarator - We previously determined (using
742/// isCXXFunctionDeclarator) that we are at a function declarator. Now parse
743/// through it.
744///
745/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
746/// exception-specification[opt]
747///
748/// exception-specification:
749/// 'throw' '(' type-id-list[opt] ')'
750///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000751Parser::TPResult Parser::TryParseFunctionDeclarator() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000752 assert(Tok.is(tok::l_paren));
753 // Parse through the parens.
754 ConsumeParen();
755 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000756 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000757
758 // cv-qualifier-seq
759 while (Tok.is(tok::kw_const) ||
760 Tok.is(tok::kw_volatile) ||
761 Tok.is(tok::kw_restrict) )
762 ConsumeToken();
763
764 // exception-specification
765 if (Tok.is(tok::kw_throw)) {
766 ConsumeToken();
767 if (Tok.isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000768 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000769
770 // Parse through the parens after 'throw'.
771 ConsumeParen();
772 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000773 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000774 }
775
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000776 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000777}
778
779/// '[' constant-expression[opt] ']'
780///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000781Parser::TPResult Parser::TryParseBracketDeclarator() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000782 ConsumeBracket();
783 if (!SkipUntil(tok::r_square))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000784 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000785
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000786 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000787}