ParseCXXInlineMethods.cpp revision 208954
1234370Sjasone//===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===// 2234370Sjasone// 3234370Sjasone// The LLVM Compiler Infrastructure 4234370Sjasone// 5234370Sjasone// This file is distributed under the University of Illinois Open Source 6234370Sjasone// License. See LICENSE.TXT for details. 7242844Sjasone// 8242844Sjasone//===----------------------------------------------------------------------===// 9234370Sjasone// 10234370Sjasone// This file implements parsing for C++ class inline methods. 11234370Sjasone// 12234370Sjasone//===----------------------------------------------------------------------===// 13234370Sjasone 14234370Sjasone#include "clang/Parse/ParseDiagnostic.h" 15234370Sjasone#include "clang/Parse/Parser.h" 16234370Sjasone#include "clang/Parse/DeclSpec.h" 17234370Sjasone#include "clang/Parse/Scope.h" 18234370Sjasoneusing namespace clang; 19242844Sjasone 20242844Sjasone/// ParseCXXInlineMethodDef - We parsed and verified that the specified 21242844Sjasone/// Declarator is a well formed C++ inline method definition. Now lex its body 22242844Sjasone/// and store its tokens for parsing after the C++ class is complete. 23234370SjasoneParser::DeclPtrTy 24234370SjasoneParser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D, 25234370Sjasone const ParsedTemplateInfo &TemplateInfo) { 26234370Sjasone assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && 27234370Sjasone "This isn't a function declarator!"); 28234370Sjasone assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && 29234370Sjasone "Current token not a '{', ':' or 'try'!"); 30234370Sjasone 31234370Sjasone Action::MultiTemplateParamsArg TemplateParams(Actions, 32234370Sjasone TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0, 33234370Sjasone TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0); 34234370Sjasone 35234370Sjasone DeclPtrTy FnD; 36242844Sjasone if (D.getDeclSpec().isFriendSpecified()) 37242844Sjasone // FIXME: Friend templates 38235238Sjasone FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, 39242844Sjasone move(TemplateParams)); 40242844Sjasone else // FIXME: pass template information through 41234370Sjasone FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 42234370Sjasone move(TemplateParams), 0, 0, 43234370Sjasone /*IsDefinition*/true); 44234370Sjasone 45242844Sjasone HandleMemberFunctionDefaultArgs(D, FnD); 46242844Sjasone 47234370Sjasone // Consume the tokens and store them for later parsing. 48234370Sjasone 49234370Sjasone getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); 50234370Sjasone getCurrentClass().MethodDefs.back().TemplateScope 51234370Sjasone = CurScope->isTemplateParamScope(); 52242844Sjasone CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; 53234370Sjasone 54235238Sjasone tok::TokenKind kind = Tok.getKind(); 55235238Sjasone // We may have a constructor initializer or function-try-block here. 56235238Sjasone if (kind == tok::colon || kind == tok::kw_try) { 57235238Sjasone // Consume everything up to (and including) the left brace. 58235238Sjasone if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) { 59235238Sjasone // We didn't find the left-brace we expected after the 60235238Sjasone // constructor initializer. 61235238Sjasone if (Tok.is(tok::semi)) { 62235238Sjasone // We found a semicolon; complain, consume the semicolon, and 63235238Sjasone // don't try to parse this method later. 64234370Sjasone Diag(Tok.getLocation(), diag::err_expected_lbrace); 65234370Sjasone ConsumeAnyToken(); 66234370Sjasone getCurrentClass().MethodDefs.pop_back(); 67234370Sjasone return FnD; 68234370Sjasone } 69234370Sjasone } 70234370Sjasone 71242844Sjasone } else { 72234370Sjasone // Begin by storing the '{' token. 73234370Sjasone Toks.push_back(Tok); 74234370Sjasone ConsumeBrace(); 75234370Sjasone } 76234370Sjasone // Consume everything up to (and including) the matching right brace. 77234370Sjasone ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); 78235238Sjasone 79235238Sjasone // If we're in a function-try-block, we need to store all the catch blocks. 80234370Sjasone if (kind == tok::kw_try) { 81245868Sjasone while (Tok.is(tok::kw_catch)) { 82245868Sjasone ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false); 83245868Sjasone ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); 84234370Sjasone } 85242844Sjasone } 86242844Sjasone 87234370Sjasone return FnD; 88234370Sjasone} 89234370Sjasone 90242844Sjasone/// ParseLexedMethodDeclarations - We finished parsing the member 91242844Sjasone/// specification of a top (non-nested) C++ class. Now go over the 92234370Sjasone/// stack of method declarations with some parts for which parsing was 93234370Sjasone/// delayed (such as default arguments) and parse them. 94234370Sjasonevoid Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { 95234370Sjasone bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; 96234370Sjasone ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); 97234370Sjasone if (HasTemplateScope) 98234370Sjasone Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate); 99234370Sjasone 100234370Sjasone // The current scope is still active if we're the top-level class. 101234370Sjasone // Otherwise we'll need to push and enter a new scope. 102234370Sjasone bool HasClassScope = !Class.TopLevelClass; 103234370Sjasone ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, 104234370Sjasone HasClassScope); 105234370Sjasone if (HasClassScope) 106234370Sjasone Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); 107234370Sjasone 108234370Sjasone for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { 109234370Sjasone LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); 110234370Sjasone 111234370Sjasone // If this is a member template, introduce the template parameter scope. 112234370Sjasone ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); 113234370Sjasone if (LM.TemplateScope) 114251300Sjasone Actions.ActOnReenterTemplateScope(CurScope, LM.Method); 115242844Sjasone 116242844Sjasone // Start the delayed C++ method declaration 117234370Sjasone Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method); 118234370Sjasone 119234370Sjasone // Introduce the parameters into scope and parse their default 120234370Sjasone // arguments. 121245868Sjasone ParseScope PrototypeScope(this, 122245868Sjasone Scope::FunctionPrototypeScope|Scope::DeclScope); 123245868Sjasone for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { 124245868Sjasone // Introduce the parameter into scope. 125245868Sjasone Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param); 126245868Sjasone 127245868Sjasone if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { 128245868Sjasone // Save the current token position. 129245868Sjasone SourceLocation origLoc = Tok.getLocation(); 130245868Sjasone 131245868Sjasone // Parse the default argument from its saved token stream. 132245868Sjasone Toks->push_back(Tok); // So that the current token doesn't get lost 133242844Sjasone PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); 134242844Sjasone 135234370Sjasone // Consume the previously-pushed token. 136234370Sjasone ConsumeAnyToken(); 137234370Sjasone 138234370Sjasone // Consume the '='. 139234370Sjasone assert(Tok.is(tok::equal) && "Default argument not starting with '='"); 140234370Sjasone SourceLocation EqualLoc = ConsumeToken(); 141234370Sjasone 142234370Sjasone OwningExprResult DefArgResult(ParseAssignmentExpression()); 143234370Sjasone if (DefArgResult.isInvalid()) 144234370Sjasone Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); 145242844Sjasone else 146242844Sjasone Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, 147234370Sjasone move(DefArgResult)); 148234370Sjasone 149234370Sjasone assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, 150234370Sjasone Tok.getLocation()) && 151234370Sjasone "ParseAssignmentExpression went over the default arg tokens!"); 152235238Sjasone // There could be leftover tokens (e.g. because of an error). 153234370Sjasone // Skip through until we reach the original token position. 154234370Sjasone while (Tok.getLocation() != origLoc) 155242844Sjasone ConsumeAnyToken(); 156242844Sjasone 157242844Sjasone delete Toks; 158242844Sjasone LM.DefaultArgs[I].Toks = 0; 159242844Sjasone } 160242844Sjasone } 161242844Sjasone PrototypeScope.Exit(); 162242844Sjasone 163242844Sjasone // Finish the delayed C++ method declaration. 164242844Sjasone Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method); 165242844Sjasone } 166234370Sjasone 167242844Sjasone for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) 168234569Sjasone ParseLexedMethodDeclarations(*Class.NestedClasses[I]); 169242844Sjasone 170242844Sjasone if (HasClassScope) 171242844Sjasone Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate); 172242844Sjasone} 173234370Sjasone 174242844Sjasone/// ParseLexedMethodDefs - We finished parsing the member specification of a top 175242844Sjasone/// (non-nested) C++ class. Now go over the stack of lexed methods that were 176234370Sjasone/// collected during its parsing and parse them all. 177234370Sjasonevoid Parser::ParseLexedMethodDefs(ParsingClass &Class) { 178234370Sjasone bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; 179234370Sjasone ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); 180234370Sjasone if (HasTemplateScope) 181251300Sjasone Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate); 182251300Sjasone 183251300Sjasone bool HasClassScope = !Class.TopLevelClass; 184251300Sjasone ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, 185251300Sjasone HasClassScope); 186251300Sjasone 187234370Sjasone for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) { 188251300Sjasone LexedMethod &LM = Class.MethodDefs.front(); 189251300Sjasone 190251300Sjasone // If this is a member template, introduce the template parameter scope. 191251300Sjasone ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope); 192251300Sjasone if (LM.TemplateScope) 193251300Sjasone Actions.ActOnReenterTemplateScope(CurScope, LM.D); 194251300Sjasone 195251300Sjasone // Save the current token position. 196251300Sjasone SourceLocation origLoc = Tok.getLocation(); 197251300Sjasone 198251300Sjasone assert(!LM.Toks.empty() && "Empty body!"); 199251300Sjasone // Append the current token at the end of the new token stream so that it 200251300Sjasone // doesn't get lost. 201251300Sjasone LM.Toks.push_back(Tok); 202251300Sjasone PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false); 203251300Sjasone 204251300Sjasone // Consume the previously pushed token. 205251300Sjasone ConsumeAnyToken(); 206251300Sjasone assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) 207234370Sjasone && "Inline method not starting with '{', ':' or 'try'"); 208234370Sjasone 209234370Sjasone // Parse the method body. Function body parsing code is similar enough 210234370Sjasone // to be re-used for method bodies as well. 211234370Sjasone ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); 212234370Sjasone Actions.ActOnStartOfFunctionDef(CurScope, LM.D); 213242844Sjasone 214242844Sjasone if (Tok.is(tok::kw_try)) { 215234370Sjasone ParseFunctionTryBlock(LM.D); 216242844Sjasone assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, 217251300Sjasone Tok.getLocation()) && 218234370Sjasone "ParseFunctionTryBlock went over the cached tokens!"); 219242844Sjasone assert(Tok.getLocation() == origLoc && 220251300Sjasone "ParseFunctionTryBlock left tokens in the token stream!"); 221234370Sjasone continue; 222235238Sjasone } 223235238Sjasone if (Tok.is(tok::colon)) { 224235238Sjasone ParseConstructorInitializer(LM.D); 225235238Sjasone 226235238Sjasone // Error recovery. 227235238Sjasone if (!Tok.is(tok::l_brace)) { 228235238Sjasone Actions.ActOnFinishFunctionBody(LM.D, Action::StmtArg(Actions)); 229251300Sjasone continue; 230251300Sjasone } 231235238Sjasone } else 232234370Sjasone Actions.ActOnDefaultCtorInitializers(LM.D); 233235238Sjasone 234242844Sjasone ParseFunctionStatementBody(LM.D); 235235238Sjasone assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc, 236235238Sjasone Tok.getLocation()) && 237235238Sjasone "We consumed more than the cached tokens!"); 238235238Sjasone assert(Tok.getLocation() == origLoc && 239235238Sjasone "Tokens were left in the token stream!"); 240235238Sjasone } 241235238Sjasone 242242844Sjasone for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) 243235238Sjasone ParseLexedMethodDefs(*Class.NestedClasses[I]); 244235238Sjasone} 245242844Sjasone 246242844Sjasone/// ConsumeAndStoreUntil - Consume and store the token at the passed token 247235238Sjasone/// container until the token 'T' is reached (which gets 248235238Sjasone/// consumed/stored too, if ConsumeFinalToken). 249235238Sjasone/// If StopAtSemi is true, then we will stop early at a ';' character. 250234370Sjasone/// Returns true if token 'T1' or 'T2' was found. 251235238Sjasone/// NOTE: This is a specialized version of Parser::SkipUntil. 252235238Sjasonebool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, 253235238Sjasone CachedTokens &Toks, 254235238Sjasone bool StopAtSemi, bool ConsumeFinalToken) { 255234370Sjasone // We always want this function to consume at least one token if the first 256251300Sjasone // token isn't T and if not at EOF. 257234370Sjasone bool isFirstTokenConsumed = true; 258235238Sjasone while (1) { 259251300Sjasone // If we found one of the tokens, stop and return true. 260235238Sjasone if (Tok.is(T1) || Tok.is(T2)) { 261235238Sjasone if (ConsumeFinalToken) { 262242844Sjasone Toks.push_back(Tok); 263242844Sjasone ConsumeAnyToken(); 264242844Sjasone } 265234370Sjasone return true; 266234370Sjasone } 267234370Sjasone 268242844Sjasone switch (Tok.getKind()) { 269234370Sjasone case tok::eof: 270234370Sjasone // Ran out of tokens. 271234370Sjasone return false; 272234370Sjasone 273234370Sjasone case tok::l_paren: 274234370Sjasone // Recursively consume properly-nested parens. 275234370Sjasone Toks.push_back(Tok); 276242844Sjasone ConsumeParen(); 277242844Sjasone ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false); 278234370Sjasone break; 279242844Sjasone case tok::l_square: 280234370Sjasone // Recursively consume properly-nested square brackets. 281234370Sjasone Toks.push_back(Tok); 282242844Sjasone ConsumeBracket(); 283242844Sjasone ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false); 284234370Sjasone break; 285251300Sjasone case tok::l_brace: 286234370Sjasone // Recursively consume properly-nested braces. 287251300Sjasone Toks.push_back(Tok); 288251300Sjasone ConsumeBrace(); 289234370Sjasone ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false); 290251300Sjasone break; 291251300Sjasone 292251300Sjasone // Okay, we found a ']' or '}' or ')', which we think should be balanced. 293251300Sjasone // Since the user wasn't looking for this token (if they were, it would 294251300Sjasone // already be handled), this isn't balanced. If there is a LHS token at a 295251300Sjasone // higher level, we will assume that this matches the unbalanced token 296251300Sjasone // and return it. Otherwise, this is a spurious RHS token, which we skip. 297251300Sjasone case tok::r_paren: 298234370Sjasone if (ParenCount && !isFirstTokenConsumed) 299234370Sjasone return false; // Matches something. 300234370Sjasone Toks.push_back(Tok); 301242844Sjasone ConsumeParen(); 302242844Sjasone break; 303242844Sjasone case tok::r_square: 304242844Sjasone if (BracketCount && !isFirstTokenConsumed) 305242844Sjasone return false; // Matches something. 306242844Sjasone Toks.push_back(Tok); 307242844Sjasone ConsumeBracket(); 308242844Sjasone break; 309242844Sjasone case tok::r_brace: 310242844Sjasone if (BraceCount && !isFirstTokenConsumed) 311242844Sjasone return false; // Matches something. 312242844Sjasone Toks.push_back(Tok); 313242844Sjasone ConsumeBrace(); 314242844Sjasone break; 315234370Sjasone 316234370Sjasone case tok::string_literal: 317234370Sjasone case tok::wide_string_literal: 318234370Sjasone Toks.push_back(Tok); 319234370Sjasone ConsumeStringToken(); 320234370Sjasone break; 321234370Sjasone case tok::semi: 322234370Sjasone if (StopAtSemi) 323234370Sjasone return false; 324234370Sjasone // FALL THROUGH. 325234370Sjasone default: 326234370Sjasone // consume this token. 327242844Sjasone Toks.push_back(Tok); 328234370Sjasone ConsumeToken(); 329234370Sjasone break; 330234370Sjasone } 331234370Sjasone isFirstTokenConsumed = false; 332242844Sjasone } 333242844Sjasone} 334234370Sjasone