blob: 95512a62693e2dbb73a73cb3d8a7587b4208a5e0 [file] [log] [blame]
Argiris Kirtzidis74b477c2008-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.
99 // isCXXDeclarationSpecifier will return TPR_ambiguous only in such a case.
100
101 TentativeParsingResult TPR = isCXXDeclarationSpecifier();
102 if (TPR != TPR_ambiguous)
103 return TPR != TPR_false; // Returns true for TPR_true or TPR_error.
104
105 // FIXME: Add statistics about the number of ambiguous statements encountered
106 // and how they were resolved (number of declarations+number of expressions).
107
108 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
109 // We need tentative parsing...
110
111 TentativeParsingAction PA(*this);
112
113 TPR = TryParseSimpleDeclaration();
114 SourceLocation TentativeParseLoc = Tok.getLocation();
115
116 PA.Revert();
117
118 // In case of an error, let the declaration parsing code handle it.
119 if (TPR == TPR_error)
120 return true;
121
122 // Declarations take precedence over expressions.
123 if (TPR == TPR_ambiguous)
124 TPR = TPR_true;
125
126 assert(TPR == TPR_true || TPR == TPR_false);
127 if (TPR == TPR_true && Tok.isNot(tok::kw_void)) {
128 // We have a declaration that looks like a functional cast; there's a high
129 // chance that the author intended the statement to be an expression.
130 // Emit a warning.
131 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
132 "declaration", SourceRange(Tok.getLocation(), TentativeParseLoc));
133 } else if (TPR == TPR_false && Tok.is(tok::kw_void)) {
134 // A functional cast to 'void' expression ? Warning..
135 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
136 "expression", SourceRange(Tok.getLocation(), TentativeParseLoc));
137 }
138
139 return TPR == TPR_true;
140}
141
142/// simple-declaration:
143/// decl-specifier-seq init-declarator-list[opt] ';'
144///
145Parser::TentativeParsingResult Parser::TryParseSimpleDeclaration() {
146 // We know that we have a simple-type-specifier/typename-specifier followed
147 // by a '('.
148 assert(isCXXDeclarationSpecifier() == TPR_ambiguous);
149
150 if (Tok.is(tok::kw_typeof))
151 TryParseTypeofSpecifier();
152 else
153 ConsumeToken();
154
155 assert(Tok.is(tok::l_paren) && "Expected '('");
156
157 TentativeParsingResult TPR = TryParseInitDeclaratorList();
158 if (TPR != TPR_ambiguous)
159 return TPR;
160
161 if (Tok.isNot(tok::semi))
162 return TPR_false;
163
164 return TPR_ambiguous;
165}
166
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000167/// init-declarator-list:
168/// init-declarator
169/// init-declarator-list ',' init-declarator
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000170///
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000171/// init-declarator:
172/// declarator initializer[opt]
173/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000174///
175/// initializer:
176/// '=' initializer-clause
177/// '(' expression-list ')'
178///
179/// initializer-clause:
180/// assignment-expression
181/// '{' initializer-list ','[opt] '}'
182/// '{' '}'
183///
184Parser::TentativeParsingResult Parser::TryParseInitDeclaratorList() {
185 // GCC only examines the first declarator for disambiguation:
186 // i.e:
187 // int(x), ++x; // GCC regards it as ill-formed declaration.
188 //
189 // Comeau and MSVC will regard the above statement as correct expression.
190 // Clang examines all of the declarators and also regards the above statement
191 // as correct expression.
192
193 while (1) {
194 // declarator
195 TentativeParsingResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
196 if (TPR != TPR_ambiguous)
197 return TPR;
198
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000199 // [GNU] simple-asm-expr[opt] attributes[opt]
200 if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
201 return TPR_true;
202
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000203 // initializer[opt]
204 if (Tok.is(tok::l_paren)) {
205 // Parse through the parens.
206 ConsumeParen();
207 if (!SkipUntil(tok::r_paren))
208 return TPR_error;
209 } else if (Tok.is(tok::equal)) {
210 // MSVC won't examine the rest of declarators if '=' is encountered, it
211 // will conclude that it is a declaration.
212 // Comeau and Clang will examine the rest of declarators.
213 // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
214 // expression.
215 //
216 // Parse through the initializer-clause.
217 SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
218 }
219
220 if (Tok.isNot(tok::comma))
221 break;
222 ConsumeToken(); // the comma.
223 }
224
225 return TPR_ambiguous;
226}
227
Argiris Kirtzidis88527fb2008-10-05 15:03:47 +0000228/// isCXXConditionDeclaration - Disambiguates between a declaration or an
229/// expression for a condition of a if/switch/while/for statement.
230/// If during the disambiguation process a parsing error is encountered,
231/// the function returns true to let the declaration parsing code handle it.
232///
233/// condition:
234/// expression
235/// type-specifier-seq declarator '=' assignment-expression
236/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
237/// '=' assignment-expression
238///
239bool Parser::isCXXConditionDeclaration() {
240 TentativeParsingResult TPR = isCXXDeclarationSpecifier();
241 if (TPR != TPR_ambiguous)
242 return TPR != TPR_false; // Returns true for TPR_true or TPR_error.
243
244 // FIXME: Add statistics about the number of ambiguous statements encountered
245 // and how they were resolved (number of declarations+number of expressions).
246
247 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
248 // We need tentative parsing...
249
250 TentativeParsingAction PA(*this);
251
252 // type-specifier-seq
253 if (Tok.is(tok::kw_typeof))
254 TryParseTypeofSpecifier();
255 else
256 ConsumeToken();
257 assert(Tok.is(tok::l_paren) && "Expected '('");
258
259 // declarator
260 TPR = TryParseDeclarator(false/*mayBeAbstract*/);
261
262 PA.Revert();
263
264 // In case of an error, let the declaration parsing code handle it.
265 if (TPR == TPR_error)
266 return true;
267
268 if (TPR == TPR_ambiguous) {
269 // '='
270 // [GNU] simple-asm-expr[opt] attributes[opt]
271 if (Tok.is(tok::equal) ||
272 Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
273 TPR = TPR_true;
274 else
275 TPR = TPR_false;
276 }
277
278 assert(TPR == TPR_true || TPR == TPR_false);
279 return TPR == TPR_true;
280}
281
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000282/// declarator:
283/// direct-declarator
284/// ptr-operator declarator
285///
286/// direct-declarator:
287/// declarator-id
288/// direct-declarator '(' parameter-declaration-clause ')'
289/// cv-qualifier-seq[opt] exception-specification[opt]
290/// direct-declarator '[' constant-expression[opt] ']'
291/// '(' declarator ')'
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000292/// [GNU] '(' attributes declarator ')'
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000293///
294/// abstract-declarator:
295/// ptr-operator abstract-declarator[opt]
296/// direct-abstract-declarator
297///
298/// direct-abstract-declarator:
299/// direct-abstract-declarator[opt]
300/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
301/// exception-specification[opt]
302/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
303/// '(' abstract-declarator ')'
304///
305/// ptr-operator:
306/// '*' cv-qualifier-seq[opt]
307/// '&'
308/// [C++0x] '&&' [TODO]
309/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
310///
311/// cv-qualifier-seq:
312/// cv-qualifier cv-qualifier-seq[opt]
313///
314/// cv-qualifier:
315/// 'const'
316/// 'volatile'
317///
318/// declarator-id:
319/// id-expression
320///
321/// id-expression:
322/// unqualified-id
323/// qualified-id [TODO]
324///
325/// unqualified-id:
326/// identifier
327/// operator-function-id [TODO]
328/// conversion-function-id [TODO]
329/// '~' class-name [TODO]
330/// template-id [TODO]
331///
332Parser::TentativeParsingResult Parser::TryParseDeclarator(bool mayBeAbstract) {
333 // declarator:
334 // direct-declarator
335 // ptr-operator declarator
336
337 while (1) {
338 if (Tok.is(tok::star) || Tok.is(tok::amp)) {
339 // ptr-operator
340 ConsumeToken();
341 while (Tok.is(tok::kw_const) ||
342 Tok.is(tok::kw_volatile) ||
343 Tok.is(tok::kw_restrict) )
344 ConsumeToken();
345 } else {
346 break;
347 }
348 }
349
350 // direct-declarator:
351 // direct-abstract-declarator:
352
353 if (Tok.is(tok::identifier)) {
354 // declarator-id
355 ConsumeToken();
356 } else if (Tok.is(tok::l_paren)) {
357 if (mayBeAbstract && isCXXFunctionDeclarator()) {
358 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
359 // exception-specification[opt]
360 TentativeParsingResult TPR = TryParseFunctionDeclarator();
361 if (TPR != TPR_ambiguous)
362 return TPR;
363 } else {
364 // '(' declarator ')'
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000365 // '(' attributes declarator ')'
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000366 // '(' abstract-declarator ')'
Argiris Kirtzidis085d1462008-10-05 14:27:18 +0000367 ConsumeParen();
368 if (Tok.is(tok::kw___attribute))
369 return TPR_true; // attributes indicate declaration
Argiris Kirtzidis74b477c2008-10-05 00:06:24 +0000370 TentativeParsingResult TPR = TryParseDeclarator(mayBeAbstract);
371 if (TPR != TPR_ambiguous)
372 return TPR;
373 if (Tok.isNot(tok::r_paren))
374 return TPR_false;
375 ConsumeParen();
376 }
377 } else if (!mayBeAbstract) {
378 return TPR_false;
379 }
380
381 while (1) {
382 TentativeParsingResult TPR;
383
384 if (Tok.is(tok::l_paren)) {
385 // direct-declarator '(' parameter-declaration-clause ')'
386 // cv-qualifier-seq[opt] exception-specification[opt]
387 if (!isCXXFunctionDeclarator())
388 break;
389 TPR = TryParseFunctionDeclarator();
390 } else if (Tok.is(tok::l_square)) {
391 // direct-declarator '[' constant-expression[opt] ']'
392 // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
393 TPR = TryParseBracketDeclarator();
394 } else {
395 break;
396 }
397
398 if (TPR != TPR_ambiguous)
399 return TPR;
400 }
401
402 return TPR_ambiguous;
403}
404
405/// isCXXDeclarationSpecifier - Returns TPR_true if it is a declaration
406/// specifier, TPR_false if it is not, TPR_ambiguous if it could be either
407/// a decl-specifier or a function-style cast, and TPR_error if a parsing
408/// error was found and reported.
409///
410/// decl-specifier:
411/// storage-class-specifier
412/// type-specifier
413/// function-specifier
414/// 'friend'
415/// 'typedef'
416/// [GNU] attributes declaration-specifiers[opt]
417///
418/// storage-class-specifier:
419/// 'register'
420/// 'static'
421/// 'extern'
422/// 'mutable'
423/// 'auto'
424/// [GNU] '__thread'
425///
426/// function-specifier:
427/// 'inline'
428/// 'virtual'
429/// 'explicit'
430///
431/// typedef-name:
432/// identifier
433///
434/// type-specifier:
435/// simple-type-specifier
436/// class-specifier
437/// enum-specifier
438/// elaborated-type-specifier
439/// typename-specifier [TODO]
440/// cv-qualifier
441///
442/// simple-type-specifier:
443/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
444/// '::'[opt] nested-name-specifier 'template'
445/// simple-template-id [TODO]
446/// 'char'
447/// 'wchar_t'
448/// 'bool'
449/// 'short'
450/// 'int'
451/// 'long'
452/// 'signed'
453/// 'unsigned'
454/// 'float'
455/// 'double'
456/// 'void'
457/// [GNU] typeof-specifier
458/// [GNU] '_Complex'
459/// [C++0x] 'auto' [TODO]
460///
461/// type-name:
462/// class-name
463/// enum-name
464/// typedef-name
465///
466/// elaborated-type-specifier:
467/// class-key '::'[opt] nested-name-specifier[opt] identifier
468/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
469/// simple-template-id
470/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
471///
472/// enum-name:
473/// identifier
474///
475/// enum-specifier:
476/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
477/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
478///
479/// class-specifier:
480/// class-head '{' member-specification[opt] '}'
481///
482/// class-head:
483/// class-key identifier[opt] base-clause[opt]
484/// class-key nested-name-specifier identifier base-clause[opt]
485/// class-key nested-name-specifier[opt] simple-template-id
486/// base-clause[opt]
487///
488/// class-key:
489/// 'class'
490/// 'struct'
491/// 'union'
492///
493/// cv-qualifier:
494/// 'const'
495/// 'volatile'
496/// [GNU] restrict
497///
498Parser::TentativeParsingResult Parser::isCXXDeclarationSpecifier() {
499 switch (Tok.getKind()) {
500 // decl-specifier:
501 // storage-class-specifier
502 // type-specifier
503 // function-specifier
504 // 'friend'
505 // 'typedef'
506
507 case tok::kw_friend:
508 case tok::kw_typedef:
509 // storage-class-specifier
510 case tok::kw_register:
511 case tok::kw_static:
512 case tok::kw_extern:
513 case tok::kw_mutable:
514 case tok::kw_auto:
515 case tok::kw___thread:
516 // function-specifier
517 case tok::kw_inline:
518 case tok::kw_virtual:
519 case tok::kw_explicit:
520
521 // type-specifier:
522 // simple-type-specifier
523 // class-specifier
524 // enum-specifier
525 // elaborated-type-specifier
526 // typename-specifier
527 // cv-qualifier
528
529 // class-specifier
530 // elaborated-type-specifier
531 case tok::kw_class:
532 case tok::kw_struct:
533 case tok::kw_union:
534 // enum-specifier
535 case tok::kw_enum:
536 // cv-qualifier
537 case tok::kw_const:
538 case tok::kw_volatile:
539
540 // GNU
541 case tok::kw_restrict:
542 case tok::kw__Complex:
543 case tok::kw___attribute:
544 return TPR_true;
545
546 // The ambiguity resides in a simple-type-specifier/typename-specifier
547 // followed by a '('. The '(' could either be the start of:
548 //
549 // direct-declarator:
550 // '(' declarator ')'
551 //
552 // direct-abstract-declarator:
553 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
554 // exception-specification[opt]
555 // '(' abstract-declarator ')'
556 //
557 // or part of a function-style cast expression:
558 //
559 // simple-type-specifier '(' expression-list[opt] ')'
560 //
561
562 // simple-type-specifier:
563
564 case tok::identifier:
565 if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
566 return TPR_false;
567 // FALL THROUGH.
568
569 case tok::kw_char:
570 case tok::kw_wchar_t:
571 case tok::kw_bool:
572 case tok::kw_short:
573 case tok::kw_int:
574 case tok::kw_long:
575 case tok::kw_signed:
576 case tok::kw_unsigned:
577 case tok::kw_float:
578 case tok::kw_double:
579 case tok::kw_void:
580 if (NextToken().is(tok::l_paren))
581 return TPR_ambiguous;
582
583 return TPR_true;
584
585 // GNU typeof support.
586 case tok::kw_typeof: {
587 if (NextToken().isNot(tok::l_paren))
588 return TPR_true;
589
590 TentativeParsingAction PA(*this);
591
592 TentativeParsingResult TPR = TryParseTypeofSpecifier();
593 bool isFollowedByParen = Tok.is(tok::l_paren);
594
595 PA.Revert();
596
597 if (TPR == TPR_error)
598 return TPR_error;
599
600 if (isFollowedByParen)
601 return TPR_ambiguous;
602
603 return TPR_true;
604 }
605
606 default:
607 return TPR_false;
608 }
609}
610
611/// [GNU] typeof-specifier:
612/// 'typeof' '(' expressions ')'
613/// 'typeof' '(' type-name ')'
614///
615Parser::TentativeParsingResult Parser::TryParseTypeofSpecifier() {
616 assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
617 ConsumeToken();
618
619 assert(Tok.is(tok::l_paren) && "Expected '('");
620 // Parse through the parens after 'typeof'.
621 ConsumeParen();
622 if (!SkipUntil(tok::r_paren))
623 return TPR_error;
624
625 return TPR_ambiguous;
626}
627
628Parser::TentativeParsingResult Parser::TryParseDeclarationSpecifier() {
629 TentativeParsingResult TPR = isCXXDeclarationSpecifier();
630 if (TPR != TPR_ambiguous)
631 return TPR;
632
633 if (Tok.is(tok::kw_typeof))
634 TryParseTypeofSpecifier();
635 else
636 ConsumeToken();
637
638 assert(Tok.is(tok::l_paren) && "Expected '('!");
639 return TPR_ambiguous;
640}
641
642/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
643/// a constructor-style initializer, when parsing declaration statements.
644/// Returns true for function declarator and false for constructor-style
645/// initializer.
646/// If during the disambiguation process a parsing error is encountered,
647/// the function returns true to let the declaration parsing code handle it.
648///
649/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
650/// exception-specification[opt]
651///
652bool Parser::isCXXFunctionDeclarator() {
653 TentativeParsingAction PA(*this);
654
655 ConsumeParen();
656 TentativeParsingResult TPR = TryParseParameterDeclarationClause();
657 if (TPR == TPR_ambiguous && Tok.isNot(tok::r_paren))
658 TPR = TPR_false;
659
660 PA.Revert();
661
662 // In case of an error, let the declaration parsing code handle it.
663 if (TPR == TPR_error)
664 return true;
665
666 // Function declarator has precedence over constructor-style initializer.
667 if (TPR == TPR_ambiguous)
668 return TPR_true;
669 return TPR == TPR_true;
670}
671
672/// parameter-declaration-clause:
673/// parameter-declaration-list[opt] '...'[opt]
674/// parameter-declaration-list ',' '...'
675///
676/// parameter-declaration-list:
677/// parameter-declaration
678/// parameter-declaration-list ',' parameter-declaration
679///
680/// parameter-declaration:
681/// decl-specifier-seq declarator
682/// decl-specifier-seq declarator '=' assignment-expression
683/// decl-specifier-seq abstract-declarator[opt]
684/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
685///
686Parser::TentativeParsingResult Parser::TryParseParameterDeclarationClause() {
687
688 if (Tok.is(tok::r_paren))
689 return TPR_true;
690
691 // parameter-declaration-list[opt] '...'[opt]
692 // parameter-declaration-list ',' '...'
693 //
694 // parameter-declaration-list:
695 // parameter-declaration
696 // parameter-declaration-list ',' parameter-declaration
697 //
698 while (1) {
699 // '...'[opt]
700 if (Tok.is(tok::ellipsis)) {
701 ConsumeToken();
702 return TPR_true; // '...' is a sign of a function declarator.
703 }
704
705 // decl-specifier-seq
706 TentativeParsingResult TPR = TryParseDeclarationSpecifier();
707 if (TPR != TPR_ambiguous)
708 return TPR;
709
710 // declarator
711 // abstract-declarator[opt]
712 TPR = TryParseDeclarator(true/*mayBeAbstract*/);
713 if (TPR != TPR_ambiguous)
714 return TPR;
715
716 if (Tok.is(tok::equal)) {
717 // '=' assignment-expression
718 // Parse through assignment-expression.
719 tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
720 if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
721 return TPR_error;
722 }
723
724 if (Tok.is(tok::ellipsis)) {
725 ConsumeToken();
726 return TPR_true; // '...' is a sign of a function declarator.
727 }
728
729 if (Tok.isNot(tok::comma))
730 break;
731 ConsumeToken(); // the comma.
732 }
733
734 return TPR_ambiguous;
735}
736
737/// TryParseFunctionDeclarator - We previously determined (using
738/// isCXXFunctionDeclarator) that we are at a function declarator. Now parse
739/// through it.
740///
741/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
742/// exception-specification[opt]
743///
744/// exception-specification:
745/// 'throw' '(' type-id-list[opt] ')'
746///
747Parser::TentativeParsingResult Parser::TryParseFunctionDeclarator() {
748 assert(Tok.is(tok::l_paren));
749 // Parse through the parens.
750 ConsumeParen();
751 if (!SkipUntil(tok::r_paren))
752 return TPR_error;
753
754 // cv-qualifier-seq
755 while (Tok.is(tok::kw_const) ||
756 Tok.is(tok::kw_volatile) ||
757 Tok.is(tok::kw_restrict) )
758 ConsumeToken();
759
760 // exception-specification
761 if (Tok.is(tok::kw_throw)) {
762 ConsumeToken();
763 if (Tok.isNot(tok::l_paren))
764 return TPR_error;
765
766 // Parse through the parens after 'throw'.
767 ConsumeParen();
768 if (!SkipUntil(tok::r_paren))
769 return TPR_error;
770 }
771
772 return TPR_ambiguous;
773}
774
775/// '[' constant-expression[opt] ']'
776///
777Parser::TentativeParsingResult Parser::TryParseBracketDeclarator() {
778 ConsumeBracket();
779 if (!SkipUntil(tok::r_square))
780 return TPR_error;
781
782 return TPR_ambiguous;
783}