ParseTentative.cpp revision 1ee2c43bc0c281b60b29f1883e1e206cae28aed6
1//===--- 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
167///       init-declarator-list:
168///         init-declarator
169///         init-declarator-list ',' init-declarator
170///
171///       init-declarator:
172///         declarator initializer[opt]
173/// [GNU]   declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
174///
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
199    // [GNU] simple-asm-expr[opt] attributes[opt]
200    if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
201      return TPR_true;
202
203    // 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
228///         declarator:
229///           direct-declarator
230///           ptr-operator declarator
231///
232///         direct-declarator:
233///           declarator-id
234///           direct-declarator '(' parameter-declaration-clause ')'
235///                 cv-qualifier-seq[opt] exception-specification[opt]
236///           direct-declarator '[' constant-expression[opt] ']'
237///           '(' declarator ')'
238/// [GNU]     '(' attributes declarator ')'
239///
240///         abstract-declarator:
241///           ptr-operator abstract-declarator[opt]
242///           direct-abstract-declarator
243///
244///         direct-abstract-declarator:
245///           direct-abstract-declarator[opt]
246///           '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
247///                 exception-specification[opt]
248///           direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
249///           '(' abstract-declarator ')'
250///
251///         ptr-operator:
252///           '*' cv-qualifier-seq[opt]
253///           '&'
254/// [C++0x]   '&&'                                                        [TODO]
255///           '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]   [TODO]
256///
257///         cv-qualifier-seq:
258///           cv-qualifier cv-qualifier-seq[opt]
259///
260///         cv-qualifier:
261///           'const'
262///           'volatile'
263///
264///         declarator-id:
265///           id-expression
266///
267///         id-expression:
268///           unqualified-id
269///           qualified-id                                                [TODO]
270///
271///         unqualified-id:
272///           identifier
273///           operator-function-id                                        [TODO]
274///           conversion-function-id                                      [TODO]
275///           '~' class-name                                              [TODO]
276///           template-id                                                 [TODO]
277///
278Parser::TentativeParsingResult Parser::TryParseDeclarator(bool mayBeAbstract) {
279  // declarator:
280  //   direct-declarator
281  //   ptr-operator declarator
282
283  while (1) {
284    if (Tok.is(tok::star) || Tok.is(tok::amp)) {
285      // ptr-operator
286      ConsumeToken();
287      while (Tok.is(tok::kw_const)    ||
288             Tok.is(tok::kw_volatile) ||
289             Tok.is(tok::kw_restrict)   )
290        ConsumeToken();
291    } else {
292      break;
293    }
294  }
295
296  // direct-declarator:
297  // direct-abstract-declarator:
298
299  if (Tok.is(tok::identifier)) {
300    // declarator-id
301    ConsumeToken();
302  } else if (Tok.is(tok::l_paren)) {
303    if (mayBeAbstract && isCXXFunctionDeclarator()) {
304      // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
305      //        exception-specification[opt]
306      TentativeParsingResult TPR = TryParseFunctionDeclarator();
307      if (TPR != TPR_ambiguous)
308        return TPR;
309    } else {
310      // '(' declarator ')'
311      // '(' attributes declarator ')'
312      // '(' abstract-declarator ')'
313      ConsumeParen();
314      if (Tok.is(tok::kw___attribute))
315        return TPR_true; // attributes indicate declaration
316      TentativeParsingResult TPR = TryParseDeclarator(mayBeAbstract);
317      if (TPR != TPR_ambiguous)
318        return TPR;
319      if (Tok.isNot(tok::r_paren))
320        return TPR_false;
321      ConsumeParen();
322    }
323  } else if (!mayBeAbstract) {
324    return TPR_false;
325  }
326
327  while (1) {
328    TentativeParsingResult TPR;
329
330    if (Tok.is(tok::l_paren)) {
331      // direct-declarator '(' parameter-declaration-clause ')'
332      //        cv-qualifier-seq[opt] exception-specification[opt]
333      if (!isCXXFunctionDeclarator())
334        break;
335      TPR = TryParseFunctionDeclarator();
336    } else if (Tok.is(tok::l_square)) {
337      // direct-declarator '[' constant-expression[opt] ']'
338      // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
339      TPR = TryParseBracketDeclarator();
340    } else {
341      break;
342    }
343
344    if (TPR != TPR_ambiguous)
345      return TPR;
346  }
347
348  return TPR_ambiguous;
349}
350
351/// isCXXDeclarationSpecifier - Returns TPR_true if it is a declaration
352/// specifier, TPR_false if it is not, TPR_ambiguous if it could be either
353/// a decl-specifier or a function-style cast, and TPR_error if a parsing
354/// error was found and reported.
355///
356///         decl-specifier:
357///           storage-class-specifier
358///           type-specifier
359///           function-specifier
360///           'friend'
361///           'typedef'
362/// [GNU]     attributes declaration-specifiers[opt]
363///
364///         storage-class-specifier:
365///           'register'
366///           'static'
367///           'extern'
368///           'mutable'
369///           'auto'
370/// [GNU]     '__thread'
371///
372///         function-specifier:
373///           'inline'
374///           'virtual'
375///           'explicit'
376///
377///         typedef-name:
378///           identifier
379///
380///         type-specifier:
381///           simple-type-specifier
382///           class-specifier
383///           enum-specifier
384///           elaborated-type-specifier
385///           typename-specifier                                    [TODO]
386///           cv-qualifier
387///
388///         simple-type-specifier:
389///           '::'[opt] nested-name-specifier[opt] type-name        [TODO]
390///           '::'[opt] nested-name-specifier 'template'
391///                 simple-template-id                              [TODO]
392///           'char'
393///           'wchar_t'
394///           'bool'
395///           'short'
396///           'int'
397///           'long'
398///           'signed'
399///           'unsigned'
400///           'float'
401///           'double'
402///           'void'
403/// [GNU]     typeof-specifier
404/// [GNU]     '_Complex'
405/// [C++0x]   'auto'                                                [TODO]
406///
407///         type-name:
408///           class-name
409///           enum-name
410///           typedef-name
411///
412///         elaborated-type-specifier:
413///           class-key '::'[opt] nested-name-specifier[opt] identifier
414///           class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
415///               simple-template-id
416///           'enum' '::'[opt] nested-name-specifier[opt] identifier
417///
418///         enum-name:
419///           identifier
420///
421///         enum-specifier:
422///           'enum' identifier[opt] '{' enumerator-list[opt] '}'
423///           'enum' identifier[opt] '{' enumerator-list ',' '}'
424///
425///         class-specifier:
426///           class-head '{' member-specification[opt] '}'
427///
428///         class-head:
429///           class-key identifier[opt] base-clause[opt]
430///           class-key nested-name-specifier identifier base-clause[opt]
431///           class-key nested-name-specifier[opt] simple-template-id
432///               base-clause[opt]
433///
434///         class-key:
435///           'class'
436///           'struct'
437///           'union'
438///
439///         cv-qualifier:
440///           'const'
441///           'volatile'
442/// [GNU]     restrict
443///
444Parser::TentativeParsingResult Parser::isCXXDeclarationSpecifier() {
445  switch (Tok.getKind()) {
446    // decl-specifier:
447    //   storage-class-specifier
448    //   type-specifier
449    //   function-specifier
450    //   'friend'
451    //   'typedef'
452
453  case tok::kw_friend:
454  case tok::kw_typedef:
455    // storage-class-specifier
456  case tok::kw_register:
457  case tok::kw_static:
458  case tok::kw_extern:
459  case tok::kw_mutable:
460  case tok::kw_auto:
461  case tok::kw___thread:
462    // function-specifier
463  case tok::kw_inline:
464  case tok::kw_virtual:
465  case tok::kw_explicit:
466
467    // type-specifier:
468    //   simple-type-specifier
469    //   class-specifier
470    //   enum-specifier
471    //   elaborated-type-specifier
472    //   typename-specifier
473    //   cv-qualifier
474
475    // class-specifier
476    // elaborated-type-specifier
477  case tok::kw_class:
478  case tok::kw_struct:
479  case tok::kw_union:
480    // enum-specifier
481  case tok::kw_enum:
482    // cv-qualifier
483  case tok::kw_const:
484  case tok::kw_volatile:
485
486    // GNU
487  case tok::kw_restrict:
488  case tok::kw__Complex:
489  case tok::kw___attribute:
490    return TPR_true;
491
492    // The ambiguity resides in a simple-type-specifier/typename-specifier
493    // followed by a '('. The '(' could either be the start of:
494    //
495    //   direct-declarator:
496    //     '(' declarator ')'
497    //
498    //   direct-abstract-declarator:
499    //     '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
500    //              exception-specification[opt]
501    //     '(' abstract-declarator ')'
502    //
503    // or part of a function-style cast expression:
504    //
505    //     simple-type-specifier '(' expression-list[opt] ')'
506    //
507
508    // simple-type-specifier:
509
510  case tok::identifier:
511    if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
512      return TPR_false;
513    // FALL THROUGH.
514
515  case tok::kw_char:
516  case tok::kw_wchar_t:
517  case tok::kw_bool:
518  case tok::kw_short:
519  case tok::kw_int:
520  case tok::kw_long:
521  case tok::kw_signed:
522  case tok::kw_unsigned:
523  case tok::kw_float:
524  case tok::kw_double:
525  case tok::kw_void:
526    if (NextToken().is(tok::l_paren))
527      return TPR_ambiguous;
528
529    return TPR_true;
530
531    // GNU typeof support.
532  case tok::kw_typeof: {
533    if (NextToken().isNot(tok::l_paren))
534      return TPR_true;
535
536    TentativeParsingAction PA(*this);
537
538    TentativeParsingResult TPR = TryParseTypeofSpecifier();
539    bool isFollowedByParen = Tok.is(tok::l_paren);
540
541    PA.Revert();
542
543    if (TPR == TPR_error)
544      return TPR_error;
545
546    if (isFollowedByParen)
547      return TPR_ambiguous;
548
549    return TPR_true;
550  }
551
552  default:
553    return TPR_false;
554  }
555}
556
557/// [GNU] typeof-specifier:
558///         'typeof' '(' expressions ')'
559///         'typeof' '(' type-name ')'
560///
561Parser::TentativeParsingResult Parser::TryParseTypeofSpecifier() {
562  assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
563  ConsumeToken();
564
565  assert(Tok.is(tok::l_paren) && "Expected '('");
566  // Parse through the parens after 'typeof'.
567  ConsumeParen();
568  if (!SkipUntil(tok::r_paren))
569    return TPR_error;
570
571  return TPR_ambiguous;
572}
573
574Parser::TentativeParsingResult Parser::TryParseDeclarationSpecifier() {
575  TentativeParsingResult TPR = isCXXDeclarationSpecifier();
576  if (TPR != TPR_ambiguous)
577    return TPR;
578
579  if (Tok.is(tok::kw_typeof))
580    TryParseTypeofSpecifier();
581  else
582    ConsumeToken();
583
584  assert(Tok.is(tok::l_paren) && "Expected '('!");
585  return TPR_ambiguous;
586}
587
588/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
589/// a constructor-style initializer, when parsing declaration statements.
590/// Returns true for function declarator and false for constructor-style
591/// initializer.
592/// If during the disambiguation process a parsing error is encountered,
593/// the function returns true to let the declaration parsing code handle it.
594///
595/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
596///         exception-specification[opt]
597///
598bool Parser::isCXXFunctionDeclarator() {
599  TentativeParsingAction PA(*this);
600
601  ConsumeParen();
602  TentativeParsingResult TPR = TryParseParameterDeclarationClause();
603  if (TPR == TPR_ambiguous && Tok.isNot(tok::r_paren))
604    TPR = TPR_false;
605
606  PA.Revert();
607
608  // In case of an error, let the declaration parsing code handle it.
609  if (TPR == TPR_error)
610    return true;
611
612  // Function declarator has precedence over constructor-style initializer.
613  if (TPR == TPR_ambiguous)
614    return TPR_true;
615  return TPR == TPR_true;
616}
617
618/// parameter-declaration-clause:
619///   parameter-declaration-list[opt] '...'[opt]
620///   parameter-declaration-list ',' '...'
621///
622/// parameter-declaration-list:
623///   parameter-declaration
624///   parameter-declaration-list ',' parameter-declaration
625///
626/// parameter-declaration:
627///   decl-specifier-seq declarator
628///   decl-specifier-seq declarator '=' assignment-expression
629///   decl-specifier-seq abstract-declarator[opt]
630///   decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
631///
632Parser::TentativeParsingResult Parser::TryParseParameterDeclarationClause() {
633
634  if (Tok.is(tok::r_paren))
635    return TPR_true;
636
637  //   parameter-declaration-list[opt] '...'[opt]
638  //   parameter-declaration-list ',' '...'
639  //
640  // parameter-declaration-list:
641  //   parameter-declaration
642  //   parameter-declaration-list ',' parameter-declaration
643  //
644  while (1) {
645    // '...'[opt]
646    if (Tok.is(tok::ellipsis)) {
647      ConsumeToken();
648      return TPR_true; // '...' is a sign of a function declarator.
649    }
650
651    // decl-specifier-seq
652    TentativeParsingResult TPR = TryParseDeclarationSpecifier();
653    if (TPR != TPR_ambiguous)
654      return TPR;
655
656    // declarator
657    // abstract-declarator[opt]
658    TPR = TryParseDeclarator(true/*mayBeAbstract*/);
659    if (TPR != TPR_ambiguous)
660      return TPR;
661
662    if (Tok.is(tok::equal)) {
663      // '=' assignment-expression
664      // Parse through assignment-expression.
665      tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
666      if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
667        return TPR_error;
668    }
669
670    if (Tok.is(tok::ellipsis)) {
671      ConsumeToken();
672      return TPR_true; // '...' is a sign of a function declarator.
673    }
674
675    if (Tok.isNot(tok::comma))
676      break;
677    ConsumeToken(); // the comma.
678  }
679
680  return TPR_ambiguous;
681}
682
683/// TryParseFunctionDeclarator - We previously determined (using
684/// isCXXFunctionDeclarator) that we are at a function declarator. Now parse
685/// through it.
686///
687/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
688///         exception-specification[opt]
689///
690/// exception-specification:
691///   'throw' '(' type-id-list[opt] ')'
692///
693Parser::TentativeParsingResult Parser::TryParseFunctionDeclarator() {
694  assert(Tok.is(tok::l_paren));
695  // Parse through the parens.
696  ConsumeParen();
697  if (!SkipUntil(tok::r_paren))
698    return TPR_error;
699
700  // cv-qualifier-seq
701  while (Tok.is(tok::kw_const)    ||
702         Tok.is(tok::kw_volatile) ||
703         Tok.is(tok::kw_restrict)   )
704    ConsumeToken();
705
706  // exception-specification
707  if (Tok.is(tok::kw_throw)) {
708    ConsumeToken();
709    if (Tok.isNot(tok::l_paren))
710      return TPR_error;
711
712    // Parse through the parens after 'throw'.
713    ConsumeParen();
714    if (!SkipUntil(tok::r_paren))
715      return TPR_error;
716  }
717
718  return TPR_ambiguous;
719}
720
721/// '[' constant-expression[opt] ']'
722///
723Parser::TentativeParsingResult Parser::TryParseBracketDeclarator() {
724  ConsumeBracket();
725  if (!SkipUntil(tok::r_square))
726    return TPR_error;
727
728  return TPR_ambiguous;
729}
730