ParseExprCXX.cpp revision e607e808c2b90724a2a6fd841e850f07de1f5b30
1//===--- ParseExprCXX.cpp - C++ Expression 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 Expression parsing implementation for C++. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Basic/Diagnostic.h" 15#include "clang/Parse/Parser.h" 16#include "clang/Parse/DeclSpec.h" 17#include "AstGuard.h" 18using namespace clang; 19 20/// MaybeParseCXXScopeSpecifier - Parse global scope or nested-name-specifier. 21/// Returns true if a nested-name-specifier was parsed from the token stream. 22/// 23/// '::'[opt] nested-name-specifier 24/// '::' 25/// 26/// nested-name-specifier: 27/// type-name '::' 28/// namespace-name '::' 29/// nested-name-specifier identifier '::' 30/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] 31/// 32bool Parser::MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS) { 33 assert(getLang().CPlusPlus && 34 "Call sites of this function should be guarded by checking for C++."); 35 36 if (Tok.is(tok::annot_cxxscope)) { 37 SS.setScopeRep(Tok.getAnnotationValue()); 38 SS.setRange(Tok.getAnnotationRange()); 39 ConsumeToken(); 40 return true; 41 } 42 43 if (Tok.isNot(tok::coloncolon) && 44 (Tok.isNot(tok::identifier) || NextToken().isNot(tok::coloncolon))) 45 return false; 46 47 // ::new and ::delete aren't nested-name-specifiers, so parsing the :: as 48 // a scope specifier only makes things more complicated. 49 if (Tok.is(tok::coloncolon)) { 50 Token Next = NextToken(); 51 if (Next.is(tok::kw_new) || Next.is(tok::kw_delete)) 52 return false; 53 } 54 55 SS.setBeginLoc(Tok.getLocation()); 56 57 // '::' 58 if (Tok.is(tok::coloncolon)) { 59 // Global scope. 60 SourceLocation CCLoc = ConsumeToken(); 61 SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc)); 62 SS.setEndLoc(CCLoc); 63 } 64 65 // nested-name-specifier: 66 // type-name '::' 67 // namespace-name '::' 68 // nested-name-specifier identifier '::' 69 // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] 70 while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) { 71 IdentifierInfo *II = Tok.getIdentifierInfo(); 72 SourceLocation IdLoc = ConsumeToken(); 73 assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!"); 74 SourceLocation CCLoc = ConsumeToken(); 75 if (SS.isInvalid()) 76 continue; 77 78 SS.setScopeRep( 79 Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II)); 80 SS.setEndLoc(CCLoc); 81 } 82 83 return true; 84} 85 86/// ParseCXXIdExpression - Handle id-expression. 87/// 88/// id-expression: 89/// unqualified-id 90/// qualified-id 91/// 92/// unqualified-id: 93/// identifier 94/// operator-function-id 95/// conversion-function-id [TODO] 96/// '~' class-name [TODO] 97/// template-id [TODO] 98/// 99/// qualified-id: 100/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id 101/// '::' identifier 102/// '::' operator-function-id 103/// '::' template-id [TODO] 104/// 105/// nested-name-specifier: 106/// type-name '::' 107/// namespace-name '::' 108/// nested-name-specifier identifier '::' 109/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO] 110/// 111/// NOTE: The standard specifies that, for qualified-id, the parser does not 112/// expect: 113/// 114/// '::' conversion-function-id 115/// '::' '~' class-name 116/// 117/// This may cause a slight inconsistency on diagnostics: 118/// 119/// class C {}; 120/// namespace A {} 121/// void f() { 122/// :: A :: ~ C(); // Some Sema error about using destructor with a 123/// // namespace. 124/// :: ~ C(); // Some Parser error like 'unexpected ~'. 125/// } 126/// 127/// We simplify the parser a bit and make it work like: 128/// 129/// qualified-id: 130/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id 131/// '::' unqualified-id 132/// 133/// That way Sema can handle and report similar errors for namespaces and the 134/// global scope. 135/// 136Parser::OwningExprResult Parser::ParseCXXIdExpression() { 137 // qualified-id: 138 // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id 139 // '::' unqualified-id 140 // 141 CXXScopeSpec SS; 142 MaybeParseCXXScopeSpecifier(SS); 143 144 // unqualified-id: 145 // identifier 146 // operator-function-id 147 // conversion-function-id 148 // '~' class-name [TODO] 149 // template-id [TODO] 150 // 151 switch (Tok.getKind()) { 152 default: 153 return ExprError(Diag(Tok, diag::err_expected_unqualified_id)); 154 155 case tok::identifier: { 156 // Consume the identifier so that we can see if it is followed by a '('. 157 IdentifierInfo &II = *Tok.getIdentifierInfo(); 158 SourceLocation L = ConsumeToken(); 159 return Owned(Actions.ActOnIdentifierExpr(CurScope, L, II, 160 Tok.is(tok::l_paren), &SS)); 161 } 162 163 case tok::kw_operator: { 164 SourceLocation OperatorLoc = Tok.getLocation(); 165 if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) { 166 return Owned(Actions.ActOnCXXOperatorFunctionIdExpr( 167 CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS)); 168 } else if (TypeTy *Type = ParseConversionFunctionId()) { 169 return Owned(Actions.ActOnCXXConversionFunctionExpr( 170 CurScope, OperatorLoc, Type, Tok.is(tok::l_paren),SS)); 171 } 172 173 // We already complained about a bad conversion-function-id, 174 // above. 175 return ExprError(); 176 } 177 178 } // switch. 179 180 assert(0 && "The switch was supposed to take care everything."); 181} 182 183/// ParseCXXCasts - This handles the various ways to cast expressions to another 184/// type. 185/// 186/// postfix-expression: [C++ 5.2p1] 187/// 'dynamic_cast' '<' type-name '>' '(' expression ')' 188/// 'static_cast' '<' type-name '>' '(' expression ')' 189/// 'reinterpret_cast' '<' type-name '>' '(' expression ')' 190/// 'const_cast' '<' type-name '>' '(' expression ')' 191/// 192Parser::OwningExprResult Parser::ParseCXXCasts() { 193 tok::TokenKind Kind = Tok.getKind(); 194 const char *CastName = 0; // For error messages 195 196 switch (Kind) { 197 default: assert(0 && "Unknown C++ cast!"); abort(); 198 case tok::kw_const_cast: CastName = "const_cast"; break; 199 case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break; 200 case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break; 201 case tok::kw_static_cast: CastName = "static_cast"; break; 202 } 203 204 SourceLocation OpLoc = ConsumeToken(); 205 SourceLocation LAngleBracketLoc = Tok.getLocation(); 206 207 if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName)) 208 return ExprError(); 209 210 TypeTy *CastTy = ParseTypeName(); 211 SourceLocation RAngleBracketLoc = Tok.getLocation(); 212 213 if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) 214 return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<"); 215 216 SourceLocation LParenLoc = Tok.getLocation(), RParenLoc; 217 218 if (Tok.isNot(tok::l_paren)) 219 return ExprError(Diag(Tok, diag::err_expected_lparen_after) << CastName); 220 221 OwningExprResult Result(ParseSimpleParenExpression(RParenLoc)); 222 223 if (!Result.isInvalid()) 224 Result = Actions.ActOnCXXNamedCast(OpLoc, Kind, 225 LAngleBracketLoc, CastTy, RAngleBracketLoc, 226 LParenLoc, Result.release(), RParenLoc); 227 228 return move(Result); 229} 230 231/// ParseCXXTypeid - This handles the C++ typeid expression. 232/// 233/// postfix-expression: [C++ 5.2p1] 234/// 'typeid' '(' expression ')' 235/// 'typeid' '(' type-id ')' 236/// 237Parser::OwningExprResult Parser::ParseCXXTypeid() { 238 assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!"); 239 240 SourceLocation OpLoc = ConsumeToken(); 241 SourceLocation LParenLoc = Tok.getLocation(); 242 SourceLocation RParenLoc; 243 244 // typeid expressions are always parenthesized. 245 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after, 246 "typeid")) 247 return ExprError(); 248 249 OwningExprResult Result(Actions); 250 251 if (isTypeIdInParens()) { 252 TypeTy *Ty = ParseTypeName(); 253 254 // Match the ')'. 255 MatchRHSPunctuation(tok::r_paren, LParenLoc); 256 257 if (!Ty) 258 return ExprError(); 259 260 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true, 261 Ty, RParenLoc); 262 } else { 263 Result = ParseExpression(); 264 265 // Match the ')'. 266 if (Result.isInvalid()) 267 SkipUntil(tok::r_paren); 268 else { 269 MatchRHSPunctuation(tok::r_paren, LParenLoc); 270 271 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false, 272 Result.release(), RParenLoc); 273 } 274 } 275 276 return move(Result); 277} 278 279/// ParseCXXBoolLiteral - This handles the C++ Boolean literals. 280/// 281/// boolean-literal: [C++ 2.13.5] 282/// 'true' 283/// 'false' 284Parser::OwningExprResult Parser::ParseCXXBoolLiteral() { 285 tok::TokenKind Kind = Tok.getKind(); 286 return Owned(Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind)); 287} 288 289/// ParseThrowExpression - This handles the C++ throw expression. 290/// 291/// throw-expression: [C++ 15] 292/// 'throw' assignment-expression[opt] 293Parser::OwningExprResult Parser::ParseThrowExpression() { 294 assert(Tok.is(tok::kw_throw) && "Not throw!"); 295 SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token. 296 297 // If the current token isn't the start of an assignment-expression, 298 // then the expression is not present. This handles things like: 299 // "C ? throw : (void)42", which is crazy but legal. 300 switch (Tok.getKind()) { // FIXME: move this predicate somewhere common. 301 case tok::semi: 302 case tok::r_paren: 303 case tok::r_square: 304 case tok::r_brace: 305 case tok::colon: 306 case tok::comma: 307 return Owned(Actions.ActOnCXXThrow(ThrowLoc)); 308 309 default: 310 OwningExprResult Expr(ParseAssignmentExpression()); 311 if (Expr.isInvalid()) return move(Expr); 312 return Owned(Actions.ActOnCXXThrow(ThrowLoc, Expr.release())); 313 } 314} 315 316/// ParseCXXThis - This handles the C++ 'this' pointer. 317/// 318/// C++ 9.3.2: In the body of a non-static member function, the keyword this is 319/// a non-lvalue expression whose value is the address of the object for which 320/// the function is called. 321Parser::OwningExprResult Parser::ParseCXXThis() { 322 assert(Tok.is(tok::kw_this) && "Not 'this'!"); 323 SourceLocation ThisLoc = ConsumeToken(); 324 return Owned(Actions.ActOnCXXThis(ThisLoc)); 325} 326 327/// ParseCXXTypeConstructExpression - Parse construction of a specified type. 328/// Can be interpreted either as function-style casting ("int(x)") 329/// or class type construction ("ClassType(x,y,z)") 330/// or creation of a value-initialized type ("int()"). 331/// 332/// postfix-expression: [C++ 5.2p1] 333/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3] 334/// typename-specifier '(' expression-list[opt] ')' [TODO] 335/// 336Parser::OwningExprResult 337Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { 338 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); 339 TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; 340 341 assert(Tok.is(tok::l_paren) && "Expected '('!"); 342 SourceLocation LParenLoc = ConsumeParen(); 343 344 ExprVector Exprs(Actions); 345 CommaLocsTy CommaLocs; 346 347 if (Tok.isNot(tok::r_paren)) { 348 if (ParseExpressionList(Exprs, CommaLocs)) { 349 SkipUntil(tok::r_paren); 350 return ExprError(); 351 } 352 } 353 354 // Match the ')'. 355 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc); 356 357 assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&& 358 "Unexpected number of commas!"); 359 return Owned(Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep, 360 LParenLoc, 361 Exprs.take(), Exprs.size(), 362 &CommaLocs[0], RParenLoc)); 363} 364 365/// ParseCXXCondition - if/switch/while/for condition expression. 366/// 367/// condition: 368/// expression 369/// type-specifier-seq declarator '=' assignment-expression 370/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt] 371/// '=' assignment-expression 372/// 373Parser::OwningExprResult Parser::ParseCXXCondition() { 374 if (!isCXXConditionDeclaration()) 375 return ParseExpression(); // expression 376 377 SourceLocation StartLoc = Tok.getLocation(); 378 379 // type-specifier-seq 380 DeclSpec DS; 381 ParseSpecifierQualifierList(DS); 382 383 // declarator 384 Declarator DeclaratorInfo(DS, Declarator::ConditionContext); 385 ParseDeclarator(DeclaratorInfo); 386 387 // simple-asm-expr[opt] 388 if (Tok.is(tok::kw_asm)) { 389 OwningExprResult AsmLabel(ParseSimpleAsm()); 390 if (AsmLabel.isInvalid()) { 391 SkipUntil(tok::semi); 392 return ExprError(); 393 } 394 DeclaratorInfo.setAsmLabel(AsmLabel.release()); 395 } 396 397 // If attributes are present, parse them. 398 if (Tok.is(tok::kw___attribute)) 399 DeclaratorInfo.AddAttributes(ParseAttributes()); 400 401 // '=' assignment-expression 402 if (Tok.isNot(tok::equal)) 403 return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator)); 404 SourceLocation EqualLoc = ConsumeToken(); 405 OwningExprResult AssignExpr(ParseAssignmentExpression()); 406 if (AssignExpr.isInvalid()) 407 return ExprError(); 408 409 return Owned(Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc, 410 DeclaratorInfo,EqualLoc, 411 AssignExpr.release())); 412} 413 414/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers. 415/// This should only be called when the current token is known to be part of 416/// simple-type-specifier. 417/// 418/// simple-type-specifier: 419/// '::'[opt] nested-name-specifier[opt] type-name 420/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO] 421/// char 422/// wchar_t 423/// bool 424/// short 425/// int 426/// long 427/// signed 428/// unsigned 429/// float 430/// double 431/// void 432/// [GNU] typeof-specifier 433/// [C++0x] auto [TODO] 434/// 435/// type-name: 436/// class-name 437/// enum-name 438/// typedef-name 439/// 440void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) { 441 // Annotate typenames and C++ scope specifiers. 442 TryAnnotateTypeOrScopeToken(); 443 444 DS.SetRangeStart(Tok.getLocation()); 445 const char *PrevSpec; 446 SourceLocation Loc = Tok.getLocation(); 447 448 switch (Tok.getKind()) { 449 default: 450 assert(0 && "Not a simple-type-specifier token!"); 451 abort(); 452 453 // type-name 454 case tok::annot_qualtypename: { 455 DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec, 456 Tok.getAnnotationValue()); 457 break; 458 } 459 460 // builtin types 461 case tok::kw_short: 462 DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec); 463 break; 464 case tok::kw_long: 465 DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec); 466 break; 467 case tok::kw_signed: 468 DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec); 469 break; 470 case tok::kw_unsigned: 471 DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec); 472 break; 473 case tok::kw_void: 474 DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec); 475 break; 476 case tok::kw_char: 477 DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec); 478 break; 479 case tok::kw_int: 480 DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec); 481 break; 482 case tok::kw_float: 483 DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec); 484 break; 485 case tok::kw_double: 486 DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec); 487 break; 488 case tok::kw_wchar_t: 489 DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec); 490 break; 491 case tok::kw_bool: 492 DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec); 493 break; 494 495 // GNU typeof support. 496 case tok::kw_typeof: 497 ParseTypeofSpecifier(DS); 498 DS.Finish(Diags, PP.getSourceManager(), getLang()); 499 return; 500 } 501 if (Tok.is(tok::annot_qualtypename)) 502 DS.SetRangeEnd(Tok.getAnnotationEndLoc()); 503 else 504 DS.SetRangeEnd(Tok.getLocation()); 505 ConsumeToken(); 506 DS.Finish(Diags, PP.getSourceManager(), getLang()); 507} 508 509/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++ 510/// [dcl.name]), which is a non-empty sequence of type-specifiers, 511/// e.g., "const short int". Note that the DeclSpec is *not* finished 512/// by parsing the type-specifier-seq, because these sequences are 513/// typically followed by some form of declarator. Returns true and 514/// emits diagnostics if this is not a type-specifier-seq, false 515/// otherwise. 516/// 517/// type-specifier-seq: [C++ 8.1] 518/// type-specifier type-specifier-seq[opt] 519/// 520bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) { 521 DS.SetRangeStart(Tok.getLocation()); 522 const char *PrevSpec = 0; 523 int isInvalid = 0; 524 525 // Parse one or more of the type specifiers. 526 if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) { 527 Diag(Tok, diag::err_operator_missing_type_specifier); 528 return true; 529 } 530 while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) ; 531 532 return false; 533} 534 535/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded 536/// operator name (C++ [over.oper]). If successful, returns the 537/// predefined identifier that corresponds to that overloaded 538/// operator. Otherwise, returns NULL and does not consume any tokens. 539/// 540/// operator-function-id: [C++ 13.5] 541/// 'operator' operator 542/// 543/// operator: one of 544/// new delete new[] delete[] 545/// + - * / % ^ & | ~ 546/// ! = < > += -= *= /= %= 547/// ^= &= |= << >> >>= <<= == != 548/// <= >= && || ++ -- , ->* -> 549/// () [] 550OverloadedOperatorKind Parser::TryParseOperatorFunctionId() { 551 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); 552 553 OverloadedOperatorKind Op = OO_None; 554 switch (NextToken().getKind()) { 555 case tok::kw_new: 556 ConsumeToken(); // 'operator' 557 ConsumeToken(); // 'new' 558 if (Tok.is(tok::l_square)) { 559 ConsumeBracket(); // '[' 560 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' 561 Op = OO_Array_New; 562 } else { 563 Op = OO_New; 564 } 565 return Op; 566 567 case tok::kw_delete: 568 ConsumeToken(); // 'operator' 569 ConsumeToken(); // 'delete' 570 if (Tok.is(tok::l_square)) { 571 ConsumeBracket(); // '[' 572 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' 573 Op = OO_Array_Delete; 574 } else { 575 Op = OO_Delete; 576 } 577 return Op; 578 579#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \ 580 case tok::Token: Op = OO_##Name; break; 581#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly) 582#include "clang/Basic/OperatorKinds.def" 583 584 case tok::l_paren: 585 ConsumeToken(); // 'operator' 586 ConsumeParen(); // '(' 587 ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')' 588 return OO_Call; 589 590 case tok::l_square: 591 ConsumeToken(); // 'operator' 592 ConsumeBracket(); // '[' 593 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']' 594 return OO_Subscript; 595 596 default: 597 return OO_None; 598 } 599 600 ConsumeToken(); // 'operator' 601 ConsumeAnyToken(); // the operator itself 602 return Op; 603} 604 605/// ParseConversionFunctionId - Parse a C++ conversion-function-id, 606/// which expresses the name of a user-defined conversion operator 607/// (C++ [class.conv.fct]p1). Returns the type that this operator is 608/// specifying a conversion for, or NULL if there was an error. 609/// 610/// conversion-function-id: [C++ 12.3.2] 611/// operator conversion-type-id 612/// 613/// conversion-type-id: 614/// type-specifier-seq conversion-declarator[opt] 615/// 616/// conversion-declarator: 617/// ptr-operator conversion-declarator[opt] 618Parser::TypeTy *Parser::ParseConversionFunctionId() { 619 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword"); 620 ConsumeToken(); // 'operator' 621 622 // Parse the type-specifier-seq. 623 DeclSpec DS; 624 if (ParseCXXTypeSpecifierSeq(DS)) 625 return 0; 626 627 // Parse the conversion-declarator, which is merely a sequence of 628 // ptr-operators. 629 Declarator D(DS, Declarator::TypeNameContext); 630 ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); 631 632 // Finish up the type. 633 Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D); 634 if (Result.isInvalid) 635 return 0; 636 else 637 return Result.Val; 638} 639 640/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate 641/// memory in a typesafe manner and call constructors. 642/// 643/// new-expression: 644/// '::'[opt] 'new' new-placement[opt] new-type-id 645/// new-initializer[opt] 646/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' 647/// new-initializer[opt] 648/// 649/// new-placement: 650/// '(' expression-list ')' 651/// 652/// new-type-id: 653/// type-specifier-seq new-declarator[opt] 654/// 655/// new-declarator: 656/// ptr-operator new-declarator[opt] 657/// direct-new-declarator 658/// 659/// new-initializer: 660/// '(' expression-list[opt] ')' 661/// [C++0x] braced-init-list [TODO] 662/// 663Parser::OwningExprResult Parser::ParseCXXNewExpression() 664{ 665 assert((Tok.is(tok::coloncolon) || Tok.is(tok::kw_new)) && 666 "Expected :: or 'new' keyword"); 667 668 SourceLocation Start = Tok.getLocation(); 669 bool UseGlobal = false; 670 if (Tok.is(tok::coloncolon)) { 671 UseGlobal = true; 672 ConsumeToken(); 673 } 674 675 assert(Tok.is(tok::kw_new) && "Lookahead should have ensured 'new'"); 676 // Consume 'new' 677 ConsumeToken(); 678 679 // A '(' now can be a new-placement or the '(' wrapping the type-id in the 680 // second form of new-expression. It can't be a new-type-id. 681 682 ExprVector PlacementArgs(Actions); 683 SourceLocation PlacementLParen, PlacementRParen; 684 685 bool ParenTypeId; 686 DeclSpec DS; 687 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); 688 if (Tok.is(tok::l_paren)) { 689 // If it turns out to be a placement, we change the type location. 690 PlacementLParen = ConsumeParen(); 691 if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) { 692 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); 693 return ExprError(); 694 } 695 696 PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen); 697 if (PlacementRParen.isInvalid()) { 698 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); 699 return ExprError(); 700 } 701 702 if (PlacementArgs.empty()) { 703 // Reset the placement locations. There was no placement. 704 PlacementLParen = PlacementRParen = SourceLocation(); 705 ParenTypeId = true; 706 } else { 707 // We still need the type. 708 if (Tok.is(tok::l_paren)) { 709 SourceLocation LParen = ConsumeParen(); 710 ParseSpecifierQualifierList(DS); 711 ParseDeclarator(DeclaratorInfo); 712 MatchRHSPunctuation(tok::r_paren, LParen); 713 ParenTypeId = true; 714 } else { 715 if (ParseCXXTypeSpecifierSeq(DS)) 716 DeclaratorInfo.setInvalidType(true); 717 else 718 ParseDeclaratorInternal(DeclaratorInfo, 719 &Parser::ParseDirectNewDeclarator); 720 ParenTypeId = false; 721 } 722 } 723 } else { 724 // A new-type-id is a simplified type-id, where essentially the 725 // direct-declarator is replaced by a direct-new-declarator. 726 if (ParseCXXTypeSpecifierSeq(DS)) 727 DeclaratorInfo.setInvalidType(true); 728 else 729 ParseDeclaratorInternal(DeclaratorInfo, 730 &Parser::ParseDirectNewDeclarator); 731 ParenTypeId = false; 732 } 733 if (DeclaratorInfo.getInvalidType()) { 734 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); 735 return ExprError(); 736 } 737 738 ExprVector ConstructorArgs(Actions); 739 SourceLocation ConstructorLParen, ConstructorRParen; 740 741 if (Tok.is(tok::l_paren)) { 742 ConstructorLParen = ConsumeParen(); 743 if (Tok.isNot(tok::r_paren)) { 744 CommaLocsTy CommaLocs; 745 if (ParseExpressionList(ConstructorArgs, CommaLocs)) { 746 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); 747 return ExprError(); 748 } 749 } 750 ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen); 751 if (ConstructorRParen.isInvalid()) { 752 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true); 753 return ExprError(); 754 } 755 } 756 757 return Owned(Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, 758 PlacementArgs.take(), PlacementArgs.size(), 759 PlacementRParen, ParenTypeId, DeclaratorInfo, 760 ConstructorLParen, ConstructorArgs.take(), 761 ConstructorArgs.size(), ConstructorRParen)); 762} 763 764/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be 765/// passed to ParseDeclaratorInternal. 766/// 767/// direct-new-declarator: 768/// '[' expression ']' 769/// direct-new-declarator '[' constant-expression ']' 770/// 771void Parser::ParseDirectNewDeclarator(Declarator &D) 772{ 773 // Parse the array dimensions. 774 bool first = true; 775 while (Tok.is(tok::l_square)) { 776 SourceLocation LLoc = ConsumeBracket(); 777 OwningExprResult Size(first ? ParseExpression() 778 : ParseConstantExpression()); 779 if (Size.isInvalid()) { 780 // Recover 781 SkipUntil(tok::r_square); 782 return; 783 } 784 first = false; 785 786 D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, 787 Size.release(), LLoc)); 788 789 if (MatchRHSPunctuation(tok::r_square, LLoc).isInvalid()) 790 return; 791 } 792} 793 794/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id. 795/// This ambiguity appears in the syntax of the C++ new operator. 796/// 797/// new-expression: 798/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' 799/// new-initializer[opt] 800/// 801/// new-placement: 802/// '(' expression-list ')' 803/// 804bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, 805 Declarator &D) 806{ 807 // The '(' was already consumed. 808 if (isTypeIdInParens()) { 809 ParseSpecifierQualifierList(D.getMutableDeclSpec()); 810 ParseDeclarator(D); 811 return D.getInvalidType(); 812 } 813 814 // It's not a type, it has to be an expression list. 815 // Discard the comma locations - ActOnCXXNew has enough parameters. 816 CommaLocsTy CommaLocs; 817 return ParseExpressionList(PlacementArgs, CommaLocs); 818} 819 820/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used 821/// to free memory allocated by new. 822/// 823/// delete-expression: 824/// '::'[opt] 'delete' cast-expression 825/// '::'[opt] 'delete' '[' ']' cast-expression 826Parser::OwningExprResult Parser::ParseCXXDeleteExpression() 827{ 828 assert((Tok.is(tok::coloncolon) || Tok.is(tok::kw_delete)) && 829 "Expected :: or 'delete' keyword"); 830 831 SourceLocation Start = Tok.getLocation(); 832 bool UseGlobal = false; 833 if (Tok.is(tok::coloncolon)) { 834 UseGlobal = true; 835 ConsumeToken(); 836 } 837 838 assert(Tok.is(tok::kw_delete) && "Lookahead should have ensured 'delete'"); 839 // Consume 'delete' 840 ConsumeToken(); 841 842 // Array delete? 843 bool ArrayDelete = false; 844 if (Tok.is(tok::l_square)) { 845 ArrayDelete = true; 846 SourceLocation LHS = ConsumeBracket(); 847 SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS); 848 if (RHS.isInvalid()) 849 return ExprError(); 850 } 851 852 OwningExprResult Operand(ParseCastExpression(false)); 853 if (Operand.isInvalid()) 854 return move(Operand); 855 856 return Owned(Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, 857 Operand.release())); 858} 859