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