/// \brief Consume tokens and store them in the passed token container until /// we've passed the try keyword and constructor initializers and have consumed /// the opening brace of the function body. The opening brace will be consumed /// if and only if there was no error. /// /// \return True on error. bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { if (Tok.is(tok::kw_try)) { Toks.push_back(Tok); ConsumeToken(); } if (Tok.is(tok::colon)) { // Initializers can contain braces too. Toks.push_back(Tok); ConsumeToken(); while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { if (Tok.is(tok::eof) || Tok.is(tok::semi)) return true; // Grab the identifier. if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) return true; tok::TokenKind kind = Tok.getKind(); Toks.push_back(Tok); if (kind == tok::l_paren) ConsumeParen(); else { assert(kind == tok::l_brace && "Must be left paren or brace here."); ConsumeBrace(); // In C++03, this has to be the start of the function body, which // means the initializer is malformed. if (!getLang().CPlusPlus0x) return false; } // Grab the initializer if (!ConsumeAndStoreUntil(kind == tok::l_paren ? tok::r_paren : tok::r_brace, Toks, /*StopAtSemi=*/true)) return true; // Grab the separating comma, if any. if (Tok.is(tok::comma)) { Toks.push_back(Tok); ConsumeToken(); } } } // Grab any remaining garbage to be diagnosed later. We stop when we reach a // brace: an opening one is the function body, while a closing one probably // means we've reached the end of the class. if (!ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) return true; if(Tok.isNot(tok::l_brace)) return true; Toks.push_back(Tok); ConsumeBrace(); return false; }
/// \brief Consume and store tokens from the '?' to the ':' in a conditional /// expression. bool Parser::ConsumeAndStoreConditional(CachedTokens &Toks) { // Consume '?'. assert(Tok.is(tok::question)); Toks.push_back(Tok); ConsumeToken(); while (Tok.isNot(tok::colon)) { if (!ConsumeAndStoreUntil(tok::question, tok::colon, Toks, /*StopAtSemi*/true, /*ConsumeFinalToken*/false)) return false; // If we found a nested conditional, consume it. if (Tok.is(tok::question) && !ConsumeAndStoreConditional(Toks)) return false; } // Consume ':'. Toks.push_back(Tok); ConsumeToken(); return true; }
/// \brief Lex a delayed template function for late parsing. void Parser::LexTemplateFunctionForLateParsing(CachedTokens &Toks) { tok::TokenKind kind = Tok.getKind(); // We may have a constructor initializer or function-try-block here. if (kind == tok::colon || kind == tok::kw_try) ConsumeAndStoreUntil(tok::l_brace, Toks); else { Toks.push_back(Tok); ConsumeBrace(); } // Consume everything up to (and including) the matching right brace. ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); // If we're in a function-try-block, we need to store all the catch blocks. if (kind == tok::kw_try) { while (Tok.is(tok::kw_catch)) { ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); } } }
/// \brief Consume tokens and store them in the passed token container until /// we've passed the try keyword and constructor initializers and have consumed /// the opening brace of the function body. The opening brace will be consumed /// if and only if there was no error. /// /// \return True on error. bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { if (Tok.is(tok::kw_try)) { Toks.push_back(Tok); ConsumeToken(); } bool ReadInitializer = false; if (Tok.is(tok::colon)) { // Initializers can contain braces too. Toks.push_back(Tok); ConsumeToken(); while (Tok.is(tok::identifier) || Tok.is(tok::coloncolon)) { if (Tok.is(tok::eof) || Tok.is(tok::semi)) return Diag(Tok.getLocation(), diag::err_expected_lbrace); // Grab the identifier. if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) return Diag(Tok.getLocation(), diag::err_expected_lparen); tok::TokenKind kind = Tok.getKind(); Toks.push_back(Tok); bool IsLParen = (kind == tok::l_paren); SourceLocation LOpen = Tok.getLocation(); if (IsLParen) { ConsumeParen(); } else { assert(kind == tok::l_brace && "Must be left paren or brace here."); ConsumeBrace(); // In C++03, this has to be the start of the function body, which // means the initializer is malformed; we'll diagnose it later. if (!getLangOpts().CPlusPlus11) return false; } // Grab the initializer if (!ConsumeAndStoreUntil(IsLParen ? tok::r_paren : tok::r_brace, Toks, /*StopAtSemi=*/true)) { Diag(Tok, IsLParen ? diag::err_expected_rparen : diag::err_expected_rbrace); Diag(LOpen, diag::note_matching) << (IsLParen ? "(" : "{"); return true; } // Grab pack ellipsis, if present if (Tok.is(tok::ellipsis)) { Toks.push_back(Tok); ConsumeToken(); } // Grab the separating comma, if any. if (Tok.is(tok::comma)) { Toks.push_back(Tok); ConsumeToken(); } else if (Tok.isNot(tok::l_brace)) { ReadInitializer = true; break; } } } // Grab any remaining garbage to be diagnosed later. We stop when we reach a // brace: an opening one is the function body, while a closing one probably // means we've reached the end of the class. ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false); if (Tok.isNot(tok::l_brace)) { if (ReadInitializer) return Diag(Tok.getLocation(), diag::err_expected_lbrace_or_comma); return Diag(Tok.getLocation(), diag::err_expected_lbrace); } Toks.push_back(Tok); ConsumeBrace(); return false; }
/// ConsumeAndStoreUntil - Consume and store the token at the passed token /// container until the token 'T' is reached (which gets /// consumed/stored too, if ConsumeFinalToken). /// If StopAtSemi is true, then we will stop early at a ';' character. /// Returns true if token 'T1' or 'T2' was found. /// NOTE: This is a specialized version of Parser::SkipUntil. bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, CachedTokens &Toks, bool StopAtSemi, bool ConsumeFinalToken) { // We always want this function to consume at least one token if the first // token isn't T and if not at EOF. bool isFirstTokenConsumed = true; while (1) { // If we found one of the tokens, stop and return true. if (Tok.is(T1) || Tok.is(T2)) { if (ConsumeFinalToken) { Toks.push_back(Tok); ConsumeAnyToken(); } return true; } switch (Tok.getKind()) { case tok::eof: // Ran out of tokens. return false; case tok::l_paren: // Recursively consume properly-nested parens. Toks.push_back(Tok); ConsumeParen(); ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); break; case tok::l_square: // Recursively consume properly-nested square brackets. Toks.push_back(Tok); ConsumeBracket(); ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); break; case tok::l_brace: // Recursively consume properly-nested braces. Toks.push_back(Tok); ConsumeBrace(); ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. // Since the user wasn't looking for this token (if they were, it would // already be handled), this isn't balanced. If there is a LHS token at a // higher level, we will assume that this matches the unbalanced token // and return it. Otherwise, this is a spurious RHS token, which we skip. case tok::r_paren: if (ParenCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeParen(); break; case tok::r_square: if (BracketCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeBracket(); break; case tok::r_brace: if (BraceCount && !isFirstTokenConsumed) return false; // Matches something. Toks.push_back(Tok); ConsumeBrace(); break; case tok::code_completion: Toks.push_back(Tok); ConsumeCodeCompletionToken(); break; case tok::string_literal: case tok::wide_string_literal: case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: Toks.push_back(Tok); ConsumeStringToken(); break; case tok::semi: if (StopAtSemi) return false; // FALL THROUGH. default: // consume this token. Toks.push_back(Tok); ConsumeToken(); break; } isFirstTokenConsumed = false; } }
/// ConsumeAndStoreInitializer - Consume and store the token at the passed token /// container until the end of the current initializer expression (either a /// default argument or an in-class initializer for a non-static data member). /// /// Returns \c true if we reached the end of something initializer-shaped, /// \c false if we bailed out. bool Parser::ConsumeAndStoreInitializer(CachedTokens &Toks, CachedInitKind CIK) { // We always want this function to consume at least one token if not at EOF. bool IsFirstToken = true; // Number of possible unclosed <s we've seen so far. These might be templates, // and might not, but if there were none of them (or we know for sure that // we're within a template), we can avoid a tentative parse. unsigned AngleCount = 0; unsigned KnownTemplateCount = 0; while (1) { switch (Tok.getKind()) { case tok::comma: // If we might be in a template, perform a tentative parse to check. if (!AngleCount) // Not a template argument: this is the end of the initializer. return true; if (KnownTemplateCount) goto consume_token; // We hit a comma inside angle brackets. This is the hard case. The // rule we follow is: // * For a default argument, if the tokens after the comma form a // syntactically-valid parameter-declaration-clause, in which each // parameter has an initializer, then this comma ends the default // argument. // * For a default initializer, if the tokens after the comma form a // syntactically-valid init-declarator-list, then this comma ends // the default initializer. { UnannotatedTentativeParsingAction PA(*this, CIK == CIK_DefaultInitializer ? tok::semi : tok::r_paren); Sema::TentativeAnalysisScope Scope(Actions); TPResult Result = TPResult::Error; ConsumeToken(); switch (CIK) { case CIK_DefaultInitializer: Result = TryParseInitDeclaratorList(); // If we parsed a complete, ambiguous init-declarator-list, this // is only syntactically-valid if it's followed by a semicolon. if (Result == TPResult::Ambiguous && Tok.isNot(tok::semi)) Result = TPResult::False; break; case CIK_DefaultArgument: bool InvalidAsDeclaration = false; Result = TryParseParameterDeclarationClause( &InvalidAsDeclaration, /*VersusTemplateArgument=*/true); // If this is an expression or a declaration with a missing // 'typename', assume it's not a declaration. if (Result == TPResult::Ambiguous && InvalidAsDeclaration) Result = TPResult::False; break; } // If what follows could be a declaration, it is a declaration. if (Result != TPResult::False && Result != TPResult::Error) { PA.Revert(); return true; } // In the uncommon case that we decide the following tokens are part // of a template argument, revert any annotations we've performed in // those tokens. We're not going to look them up until we've parsed // the rest of the class, and that might add more declarations. PA.RevertAnnotations(); } // Keep going. We know we're inside a template argument list now. ++KnownTemplateCount; goto consume_token; case tok::eof: case tok::annot_module_begin: case tok::annot_module_end: case tok::annot_module_include: // Ran out of tokens. return false; case tok::less: // FIXME: A '<' can only start a template-id if it's preceded by an // identifier, an operator-function-id, or a literal-operator-id. ++AngleCount; goto consume_token; case tok::question: // In 'a ? b : c', 'b' can contain an unparenthesized comma. If it does, // that is *never* the end of the initializer. Skip to the ':'. if (!ConsumeAndStoreConditional(Toks)) return false; break; case tok::greatergreatergreater: if (!getLangOpts().CPlusPlus11) goto consume_token; if (AngleCount) --AngleCount; if (KnownTemplateCount) --KnownTemplateCount; // Fall through. case tok::greatergreater: if (!getLangOpts().CPlusPlus11) goto consume_token; if (AngleCount) --AngleCount; if (KnownTemplateCount) --KnownTemplateCount; // Fall through. case tok::greater: if (AngleCount) --AngleCount; if (KnownTemplateCount) --KnownTemplateCount; goto consume_token; case tok::kw_template: // 'template' identifier '<' is known to start a template argument list, // and can be used to disambiguate the parse. // FIXME: Support all forms of 'template' unqualified-id '<'. Toks.push_back(Tok); ConsumeToken(); if (Tok.is(tok::identifier)) { Toks.push_back(Tok); ConsumeToken(); if (Tok.is(tok::less)) { ++AngleCount; ++KnownTemplateCount; Toks.push_back(Tok); ConsumeToken(); } } break; case tok::kw_operator: // If 'operator' precedes other punctuation, that punctuation loses // its special behavior. Toks.push_back(Tok); ConsumeToken(); switch (Tok.getKind()) { case tok::comma: case tok::greatergreatergreater: case tok::greatergreater: case tok::greater: case tok::less: Toks.push_back(Tok); ConsumeToken(); break; default: break; } break; case tok::l_paren: // Recursively consume properly-nested parens. Toks.push_back(Tok); ConsumeParen(); ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); break; case tok::l_square: // Recursively consume properly-nested square brackets. Toks.push_back(Tok); ConsumeBracket(); ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); break; case tok::l_brace: // Recursively consume properly-nested braces. Toks.push_back(Tok); ConsumeBrace(); ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); break; // Okay, we found a ']' or '}' or ')', which we think should be balanced. // Since the user wasn't looking for this token (if they were, it would // already be handled), this isn't balanced. If there is a LHS token at a // higher level, we will assume that this matches the unbalanced token // and return it. Otherwise, this is a spurious RHS token, which we // consume and pass on to downstream code to diagnose. case tok::r_paren: if (CIK == CIK_DefaultArgument) return true; // End of the default argument. if (ParenCount && !IsFirstToken) return false; Toks.push_back(Tok); ConsumeParen(); continue; case tok::r_square: if (BracketCount && !IsFirstToken) return false; Toks.push_back(Tok); ConsumeBracket(); continue; case tok::r_brace: if (BraceCount && !IsFirstToken) return false; Toks.push_back(Tok); ConsumeBrace(); continue; case tok::code_completion: Toks.push_back(Tok); ConsumeCodeCompletionToken(); break; case tok::string_literal: case tok::wide_string_literal: case tok::utf8_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: Toks.push_back(Tok); ConsumeStringToken(); break; case tok::semi: if (CIK == CIK_DefaultInitializer) return true; // End of the default initializer. // FALL THROUGH. default: consume_token: Toks.push_back(Tok); ConsumeToken(); break; } IsFirstToken = false; } }
/// \brief Consume tokens and store them in the passed token container until /// we've passed the try keyword and constructor initializers and have consumed /// the opening brace of the function body. The opening brace will be consumed /// if and only if there was no error. /// /// \return True on error. bool Parser::ConsumeAndStoreFunctionPrologue(CachedTokens &Toks) { if (Tok.is(tok::kw_try)) { Toks.push_back(Tok); ConsumeToken(); } if (Tok.isNot(tok::colon)) { // Easy case, just a function body. // Grab any remaining garbage to be diagnosed later. We stop when we reach a // brace: an opening one is the function body, while a closing one probably // means we've reached the end of the class. ConsumeAndStoreUntil(tok::l_brace, tok::r_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false); if (Tok.isNot(tok::l_brace)) return Diag(Tok.getLocation(), diag::err_expected) << tok::l_brace; Toks.push_back(Tok); ConsumeBrace(); return false; } Toks.push_back(Tok); ConsumeToken(); // We can't reliably skip over a mem-initializer-id, because it could be // a template-id involving not-yet-declared names. Given: // // S ( ) : a < b < c > ( e ) // // 'e' might be an initializer or part of a template argument, depending // on whether 'b' is a template. // Track whether we might be inside a template argument. We can give // significantly better diagnostics if we know that we're not. bool MightBeTemplateArgument = false; while (true) { // Skip over the mem-initializer-id, if possible. if (Tok.is(tok::kw_decltype)) { Toks.push_back(Tok); SourceLocation OpenLoc = ConsumeToken(); if (Tok.isNot(tok::l_paren)) return Diag(Tok.getLocation(), diag::err_expected_lparen_after) << "decltype"; Toks.push_back(Tok); ConsumeParen(); if (!ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/true)) { Diag(Tok.getLocation(), diag::err_expected) << tok::r_paren; Diag(OpenLoc, diag::note_matching) << tok::l_paren; return true; } } do { // Walk over a component of a nested-name-specifier. if (Tok.is(tok::coloncolon)) { Toks.push_back(Tok); ConsumeToken(); if (Tok.is(tok::kw_template)) { Toks.push_back(Tok); ConsumeToken(); } } if (Tok.is(tok::identifier) || Tok.is(tok::kw_template)) { Toks.push_back(Tok); ConsumeToken(); } else if (Tok.is(tok::code_completion)) { Toks.push_back(Tok); ConsumeCodeCompletionToken(); // Consume the rest of the initializers permissively. // FIXME: We should be able to perform code-completion here even if // there isn't a subsequent '{' token. MightBeTemplateArgument = true; break; } else { break; } } while (Tok.is(tok::coloncolon)); if (Tok.is(tok::less)) MightBeTemplateArgument = true; if (MightBeTemplateArgument) { // We may be inside a template argument list. Grab up to the start of the // next parenthesized initializer or braced-init-list. This *might* be the // initializer, or it might be a subexpression in the template argument // list. // FIXME: Count angle brackets, and clear MightBeTemplateArgument // if all angles are closed. if (!ConsumeAndStoreUntil(tok::l_paren, tok::l_brace, Toks, /*StopAtSemi=*/true, /*ConsumeFinalToken=*/false)) { // We're not just missing the initializer, we're also missing the // function body! return Diag(Tok.getLocation(), diag::err_expected) << tok::l_brace; } } else if (Tok.isNot(tok::l_paren) && Tok.isNot(tok::l_brace)) { // We found something weird in a mem-initializer-id. if (getLangOpts().CPlusPlus11) return Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_paren << tok::l_brace; else return Diag(Tok.getLocation(), diag::err_expected) << tok::l_paren; } tok::TokenKind kind = Tok.getKind(); Toks.push_back(Tok); bool IsLParen = (kind == tok::l_paren); SourceLocation OpenLoc = Tok.getLocation(); if (IsLParen) { ConsumeParen(); } else { assert(kind == tok::l_brace && "Must be left paren or brace here."); ConsumeBrace(); // In C++03, this has to be the start of the function body, which // means the initializer is malformed; we'll diagnose it later. if (!getLangOpts().CPlusPlus11) return false; } // Grab the initializer (or the subexpression of the template argument). // FIXME: If we support lambdas here, we'll need to set StopAtSemi to false // if we might be inside the braces of a lambda-expression. tok::TokenKind CloseKind = IsLParen ? tok::r_paren : tok::r_brace; if (!ConsumeAndStoreUntil(CloseKind, Toks, /*StopAtSemi=*/true)) { Diag(Tok, diag::err_expected) << CloseKind; Diag(OpenLoc, diag::note_matching) << kind; return true; } // Grab pack ellipsis, if present. if (Tok.is(tok::ellipsis)) { Toks.push_back(Tok); ConsumeToken(); } // If we know we just consumed a mem-initializer, we must have ',' or '{' // next. if (Tok.is(tok::comma)) { Toks.push_back(Tok); ConsumeToken(); } else if (Tok.is(tok::l_brace)) { // This is the function body if the ')' or '}' is immediately followed by // a '{'. That cannot happen within a template argument, apart from the // case where a template argument contains a compound literal: // // S ( ) : a < b < c > ( d ) { } // // End of declaration, or still inside the template argument? // // ... and the case where the template argument contains a lambda: // // S ( ) : a < 0 && b < c > ( d ) + [ ] ( ) { return 0; } // ( ) > ( ) { } // // FIXME: Disambiguate these cases. Note that the latter case is probably // going to be made ill-formed by core issue 1607. Toks.push_back(Tok); ConsumeBrace(); return false; } else if (!MightBeTemplateArgument) { return Diag(Tok.getLocation(), diag::err_expected_either) << tok::l_brace << tok::comma; } } }