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