ParseCXXInlineMethods.cpp revision 6569d68745c8213709740337d2be52b031384f58
1//===--- ParseCXXInlineMethods.cpp - C++ class inline methods 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 parsing for C++ class inline methods. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/Parse/ParseDiagnostic.h" 15#include "clang/Parse/Parser.h" 16#include "clang/Parse/DeclSpec.h" 17#include "clang/Parse/Scope.h" 18using namespace clang; 19 20/// ParseCXXInlineMethodDef - We parsed and verified that the specified 21/// Declarator is a well formed C++ inline method definition. Now lex its body 22/// and store its tokens for parsing after the C++ class is complete. 23Parser::DeclPtrTy 24Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D) { 25 assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function && 26 "This isn't a function declarator!"); 27 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) && 28 "Current token not a '{', ':' or 'try'!"); 29 30 DeclPtrTy FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D, 0, 0); 31 32 // Consume the tokens and store them for later parsing. 33 34 getCurrentClass().MethodDefs.push_back(LexedMethod(FnD)); 35 CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks; 36 37 tok::TokenKind kind = Tok.getKind(); 38 // We may have a constructor initializer or function-try-block here. 39 if (kind == tok::colon || kind == tok::kw_try) { 40 // Consume everything up to (and including) the left brace. 41 if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) { 42 // We didn't find the left-brace we expected after the 43 // constructor initializer. 44 if (Tok.is(tok::semi)) { 45 // We found a semicolon; complain, consume the semicolon, and 46 // don't try to parse this method later. 47 Diag(Tok.getLocation(), diag::err_expected_lbrace); 48 ConsumeAnyToken(); 49 getCurrentClass().MethodDefs.pop_back(); 50 return FnD; 51 } 52 } 53 54 } else { 55 // Begin by storing the '{' token. 56 Toks.push_back(Tok); 57 ConsumeBrace(); 58 } 59 // Consume everything up to (and including) the matching right brace. 60 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); 61 62 // If we're in a function-try-block, we need to store all the catch blocks. 63 if (kind == tok::kw_try) { 64 while (Tok.is(tok::kw_catch)) { 65 ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks); 66 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); 67 } 68 } 69 70 return FnD; 71} 72 73/// ParseLexedMethodDeclarations - We finished parsing the member 74/// specification of a top (non-nested) C++ class. Now go over the 75/// stack of method declarations with some parts for which parsing was 76/// delayed (such as default arguments) and parse them. 77void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) { 78 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; 79 ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); 80 if (HasTemplateScope) 81 Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate); 82 83 bool HasClassScope = !Class.TopLevelClass; 84 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, 85 HasClassScope); 86 87 for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) { 88 LateParsedMethodDeclaration &LM = Class.MethodDecls.front(); 89 90 // FIXME: For member function templates, we'll need to introduce a 91 // scope for the template parameters. 92 93 // Start the delayed C++ method declaration 94 Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method); 95 96 // Introduce the parameters into scope and parse their default 97 // arguments. 98 ParseScope PrototypeScope(this, 99 Scope::FunctionPrototypeScope|Scope::DeclScope); 100 for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) { 101 // Introduce the parameter into scope. 102 Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param); 103 104 if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) { 105 // Parse the default argument from its saved token stream. 106 Toks->push_back(Tok); // So that the current token doesn't get lost 107 PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false); 108 109 // Consume the previously-pushed token. 110 ConsumeAnyToken(); 111 112 // Consume the '='. 113 assert(Tok.is(tok::equal) && "Default argument not starting with '='"); 114 SourceLocation EqualLoc = ConsumeToken(); 115 116 OwningExprResult DefArgResult(ParseAssignmentExpression()); 117 if (DefArgResult.isInvalid()) 118 Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param); 119 else 120 Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc, 121 move(DefArgResult)); 122 delete Toks; 123 LM.DefaultArgs[I].Toks = 0; 124 } 125 } 126 PrototypeScope.Exit(); 127 128 // Finish the delayed C++ method declaration. 129 Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method); 130 } 131 132 for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) 133 ParseLexedMethodDeclarations(*Class.NestedClasses[I]); 134} 135 136/// ParseLexedMethodDefs - We finished parsing the member specification of a top 137/// (non-nested) C++ class. Now go over the stack of lexed methods that were 138/// collected during its parsing and parse them all. 139void Parser::ParseLexedMethodDefs(ParsingClass &Class) { 140 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope; 141 ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope); 142 if (HasTemplateScope) 143 Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate); 144 145 bool HasClassScope = !Class.TopLevelClass; 146 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, 147 HasClassScope); 148 149 for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) { 150 LexedMethod &LM = Class.MethodDefs.front(); 151 152 assert(!LM.Toks.empty() && "Empty body!"); 153 // Append the current token at the end of the new token stream so that it 154 // doesn't get lost. 155 LM.Toks.push_back(Tok); 156 PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false); 157 158 // Consume the previously pushed token. 159 ConsumeAnyToken(); 160 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) 161 && "Inline method not starting with '{', ':' or 'try'"); 162 163 // Parse the method body. Function body parsing code is similar enough 164 // to be re-used for method bodies as well. 165 ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope); 166 Actions.ActOnStartOfFunctionDef(CurScope, LM.D); 167 168 if (Tok.is(tok::kw_try)) { 169 ParseFunctionTryBlock(LM.D); 170 continue; 171 } 172 if (Tok.is(tok::colon)) 173 ParseConstructorInitializer(LM.D); 174 // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'?? 175 ParseFunctionStatementBody(LM.D); 176 } 177 178 for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I) 179 ParseLexedMethodDefs(*Class.NestedClasses[I]); 180} 181 182/// ConsumeAndStoreUntil - Consume and store the token at the passed token 183/// container until the token 'T' is reached (which gets 184/// consumed/stored too, if ConsumeFinalToken). 185/// If EarlyAbortIf is specified, then we will stop early if we find that 186/// token at the top level. 187/// Returns true if token 'T1' or 'T2' was found. 188/// NOTE: This is a specialized version of Parser::SkipUntil. 189bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2, 190 CachedTokens &Toks, 191 tok::TokenKind EarlyAbortIf, 192 bool ConsumeFinalToken) { 193 // We always want this function to consume at least one token if the first 194 // token isn't T and if not at EOF. 195 bool isFirstTokenConsumed = true; 196 while (1) { 197 // If we found one of the tokens, stop and return true. 198 if (Tok.is(T1) || Tok.is(T2)) { 199 if (ConsumeFinalToken) { 200 Toks.push_back(Tok); 201 ConsumeAnyToken(); 202 } 203 return true; 204 } 205 206 // If we found the early-abort token, return. 207 if (Tok.is(EarlyAbortIf)) 208 return false; 209 210 switch (Tok.getKind()) { 211 case tok::eof: 212 // Ran out of tokens. 213 return false; 214 215 case tok::l_paren: 216 // Recursively consume properly-nested parens. 217 Toks.push_back(Tok); 218 ConsumeParen(); 219 ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks); 220 break; 221 case tok::l_square: 222 // Recursively consume properly-nested square brackets. 223 Toks.push_back(Tok); 224 ConsumeBracket(); 225 ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks); 226 break; 227 case tok::l_brace: 228 // Recursively consume properly-nested braces. 229 Toks.push_back(Tok); 230 ConsumeBrace(); 231 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks); 232 break; 233 234 // Okay, we found a ']' or '}' or ')', which we think should be balanced. 235 // Since the user wasn't looking for this token (if they were, it would 236 // already be handled), this isn't balanced. If there is a LHS token at a 237 // higher level, we will assume that this matches the unbalanced token 238 // and return it. Otherwise, this is a spurious RHS token, which we skip. 239 case tok::r_paren: 240 if (ParenCount && !isFirstTokenConsumed) 241 return false; // Matches something. 242 Toks.push_back(Tok); 243 ConsumeParen(); 244 break; 245 case tok::r_square: 246 if (BracketCount && !isFirstTokenConsumed) 247 return false; // Matches something. 248 Toks.push_back(Tok); 249 ConsumeBracket(); 250 break; 251 case tok::r_brace: 252 if (BraceCount && !isFirstTokenConsumed) 253 return false; // Matches something. 254 Toks.push_back(Tok); 255 ConsumeBrace(); 256 break; 257 258 case tok::string_literal: 259 case tok::wide_string_literal: 260 Toks.push_back(Tok); 261 ConsumeStringToken(); 262 break; 263 default: 264 // consume this token. 265 Toks.push_back(Tok); 266 ConsumeToken(); 267 break; 268 } 269 isFirstTokenConsumed = false; 270 } 271} 272