blob: 80feff42d7ffc9035b7d4637dbc17e372a405b02 [file] [log] [blame]
Argiris Kirtzidis9d784332008-06-24 22:12:16 +00001//===--- 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
Chris Lattner545f39e2009-01-29 05:15:15 +000014#include "clang/Parse/ParseDiagnostic.h"
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000015#include "clang/Parse/Parser.h"
16#include "clang/Parse/DeclSpec.h"
17#include "clang/Parse/Scope.h"
18using namespace clang;
19
Sebastian Redlbc9ef252009-04-26 20:35:05 +000020/// ParseCXXInlineMethodDef - We parsed and verified that the specified
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000021/// 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.
Chris Lattner5261d0c2009-03-28 19:18:32 +000023Parser::DeclPtrTy
Douglas Gregor398a8012009-08-20 22:52:58 +000024Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
25 const ParsedTemplateInfo &TemplateInfo) {
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000026 assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
27 "This isn't a function declarator!");
Sebastian Redlbc9ef252009-04-26 20:35:05 +000028 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
29 "Current token not a '{', ':' or 'try'!");
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000030
Douglas Gregor398a8012009-08-20 22:52:58 +000031 Action::MultiTemplateParamsArg TemplateParams(Actions,
32 TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
33 TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
John McCall140607b2009-08-06 02:15:43 +000034 DeclPtrTy FnD;
35 if (D.getDeclSpec().isFriendSpecified())
Douglas Gregor398a8012009-08-20 22:52:58 +000036 // FIXME: Friend templates
John McCall36493082009-08-11 06:59:38 +000037 FnD = Actions.ActOnFriendDecl(CurScope, &D, /*IsDefinition*/ true);
Douglas Gregor398a8012009-08-20 22:52:58 +000038 else // FIXME: pass template information through
39 FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
40 move(TemplateParams), 0, 0);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000041
Eli Friedman40035e22009-07-22 21:45:50 +000042 HandleMemberFunctionDefaultArgs(D, FnD);
43
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000044 // Consume the tokens and store them for later parsing.
45
Douglas Gregora376cbd2009-05-27 23:11:45 +000046 getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
47 CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks;
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000048
Sebastian Redlbc9ef252009-04-26 20:35:05 +000049 tok::TokenKind kind = Tok.getKind();
50 // We may have a constructor initializer or function-try-block here.
51 if (kind == tok::colon || kind == tok::kw_try) {
Douglas Gregora65e8dd2008-11-05 04:29:56 +000052 // Consume everything up to (and including) the left brace.
Douglas Gregor605de8d2008-12-16 21:30:33 +000053 if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
Douglas Gregord2c14ad2008-11-10 16:59:40 +000054 // We didn't find the left-brace we expected after the
55 // constructor initializer.
56 if (Tok.is(tok::semi)) {
57 // We found a semicolon; complain, consume the semicolon, and
58 // don't try to parse this method later.
59 Diag(Tok.getLocation(), diag::err_expected_lbrace);
60 ConsumeAnyToken();
Douglas Gregora376cbd2009-05-27 23:11:45 +000061 getCurrentClass().MethodDefs.pop_back();
Douglas Gregord2c14ad2008-11-10 16:59:40 +000062 return FnD;
63 }
64 }
65
Douglas Gregora65e8dd2008-11-05 04:29:56 +000066 } else {
67 // Begin by storing the '{' token.
68 Toks.push_back(Tok);
69 ConsumeBrace();
70 }
71 // Consume everything up to (and including) the matching right brace.
Douglas Gregor605de8d2008-12-16 21:30:33 +000072 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000073
Sebastian Redlbc9ef252009-04-26 20:35:05 +000074 // If we're in a function-try-block, we need to store all the catch blocks.
75 if (kind == tok::kw_try) {
76 while (Tok.is(tok::kw_catch)) {
77 ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
78 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
79 }
80 }
81
Argiris Kirtzidis9d784332008-06-24 22:12:16 +000082 return FnD;
83}
84
Douglas Gregor605de8d2008-12-16 21:30:33 +000085/// ParseLexedMethodDeclarations - We finished parsing the member
86/// specification of a top (non-nested) C++ class. Now go over the
87/// stack of method declarations with some parts for which parsing was
88/// delayed (such as default arguments) and parse them.
Douglas Gregora376cbd2009-05-27 23:11:45 +000089void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
90 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
91 ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
92 if (HasTemplateScope)
93 Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
94
95 bool HasClassScope = !Class.TopLevelClass;
96 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
97 HasClassScope);
98
99 for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
100 LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
Douglas Gregor605de8d2008-12-16 21:30:33 +0000101
Douglas Gregora376cbd2009-05-27 23:11:45 +0000102 // FIXME: For member function templates, we'll need to introduce a
103 // scope for the template parameters.
104
Douglas Gregor605de8d2008-12-16 21:30:33 +0000105 // Start the delayed C++ method declaration
106 Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
107
108 // Introduce the parameters into scope and parse their default
109 // arguments.
Douglas Gregorcab994d2009-01-09 22:42:13 +0000110 ParseScope PrototypeScope(this,
111 Scope::FunctionPrototypeScope|Scope::DeclScope);
Douglas Gregor605de8d2008-12-16 21:30:33 +0000112 for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
113 // Introduce the parameter into scope.
114 Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);
115
116 if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
117 // Parse the default argument from its saved token stream.
118 Toks->push_back(Tok); // So that the current token doesn't get lost
119 PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
120
121 // Consume the previously-pushed token.
122 ConsumeAnyToken();
123
124 // Consume the '='.
125 assert(Tok.is(tok::equal) && "Default argument not starting with '='");
126 SourceLocation EqualLoc = ConsumeToken();
127
128 OwningExprResult DefArgResult(ParseAssignmentExpression());
129 if (DefArgResult.isInvalid())
130 Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
131 else
132 Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
Sebastian Redl76bb8ec2009-03-15 17:47:39 +0000133 move(DefArgResult));
Douglas Gregor605de8d2008-12-16 21:30:33 +0000134 delete Toks;
135 LM.DefaultArgs[I].Toks = 0;
136 }
137 }
138 PrototypeScope.Exit();
139
140 // Finish the delayed C++ method declaration.
141 Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);
142 }
Douglas Gregora376cbd2009-05-27 23:11:45 +0000143
144 for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
145 ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
Douglas Gregor605de8d2008-12-16 21:30:33 +0000146}
147
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000148/// ParseLexedMethodDefs - We finished parsing the member specification of a top
149/// (non-nested) C++ class. Now go over the stack of lexed methods that were
150/// collected during its parsing and parse them all.
Douglas Gregora376cbd2009-05-27 23:11:45 +0000151void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
152 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
153 ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
154 if (HasTemplateScope)
155 Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
156
157 bool HasClassScope = !Class.TopLevelClass;
158 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
159 HasClassScope);
160
161 for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
162 LexedMethod &LM = Class.MethodDefs.front();
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000163
164 assert(!LM.Toks.empty() && "Empty body!");
165 // Append the current token at the end of the new token stream so that it
166 // doesn't get lost.
167 LM.Toks.push_back(Tok);
168 PP.EnterTokenStream(&LM.Toks.front(), LM.Toks.size(), true, false);
169
170 // Consume the previously pushed token.
171 ConsumeAnyToken();
Sebastian Redlbc9ef252009-04-26 20:35:05 +0000172 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
173 && "Inline method not starting with '{', ':' or 'try'");
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000174
175 // Parse the method body. Function body parsing code is similar enough
176 // to be re-used for method bodies as well.
Douglas Gregor95d40792008-12-10 06:34:36 +0000177 ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000178 Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
179
Sebastian Redlbc9ef252009-04-26 20:35:05 +0000180 if (Tok.is(tok::kw_try)) {
181 ParseFunctionTryBlock(LM.D);
Sebastian Redl8b772d32009-04-26 21:08:36 +0000182 continue;
Sebastian Redlbc9ef252009-04-26 20:35:05 +0000183 }
Douglas Gregora65e8dd2008-11-05 04:29:56 +0000184 if (Tok.is(tok::colon))
185 ParseConstructorInitializer(LM.D);
Fariborz Jahanianbc397fc2009-07-14 20:06:22 +0000186 else
Fariborz Jahanian4e127232009-07-21 22:36:06 +0000187 Actions.ActOnDefaultCtorInitializers(LM.D);
Fariborz Jahanian9294d192009-07-14 18:24:21 +0000188
Chris Lattner0818a7a2009-03-05 00:49:17 +0000189 // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
190 ParseFunctionStatementBody(LM.D);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000191 }
Douglas Gregora376cbd2009-05-27 23:11:45 +0000192
193 for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
194 ParseLexedMethodDefs(*Class.NestedClasses[I]);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000195}
196
197/// ConsumeAndStoreUntil - Consume and store the token at the passed token
Douglas Gregor605de8d2008-12-16 21:30:33 +0000198/// container until the token 'T' is reached (which gets
199/// consumed/stored too, if ConsumeFinalToken).
Douglas Gregord2c14ad2008-11-10 16:59:40 +0000200/// If EarlyAbortIf is specified, then we will stop early if we find that
201/// token at the top level.
Douglas Gregor605de8d2008-12-16 21:30:33 +0000202/// Returns true if token 'T1' or 'T2' was found.
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000203/// NOTE: This is a specialized version of Parser::SkipUntil.
Douglas Gregor605de8d2008-12-16 21:30:33 +0000204bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
205 CachedTokens &Toks,
206 tok::TokenKind EarlyAbortIf,
207 bool ConsumeFinalToken) {
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000208 // We always want this function to consume at least one token if the first
209 // token isn't T and if not at EOF.
210 bool isFirstTokenConsumed = true;
211 while (1) {
212 // If we found one of the tokens, stop and return true.
Douglas Gregor605de8d2008-12-16 21:30:33 +0000213 if (Tok.is(T1) || Tok.is(T2)) {
214 if (ConsumeFinalToken) {
215 Toks.push_back(Tok);
216 ConsumeAnyToken();
217 }
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000218 return true;
219 }
220
Douglas Gregord2c14ad2008-11-10 16:59:40 +0000221 // If we found the early-abort token, return.
222 if (Tok.is(EarlyAbortIf))
223 return false;
224
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000225 switch (Tok.getKind()) {
226 case tok::eof:
227 // Ran out of tokens.
228 return false;
229
230 case tok::l_paren:
231 // Recursively consume properly-nested parens.
232 Toks.push_back(Tok);
233 ConsumeParen();
Douglas Gregor605de8d2008-12-16 21:30:33 +0000234 ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000235 break;
236 case tok::l_square:
237 // Recursively consume properly-nested square brackets.
238 Toks.push_back(Tok);
239 ConsumeBracket();
Douglas Gregor605de8d2008-12-16 21:30:33 +0000240 ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000241 break;
242 case tok::l_brace:
243 // Recursively consume properly-nested braces.
244 Toks.push_back(Tok);
245 ConsumeBrace();
Douglas Gregor605de8d2008-12-16 21:30:33 +0000246 ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000247 break;
248
249 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
250 // Since the user wasn't looking for this token (if they were, it would
251 // already be handled), this isn't balanced. If there is a LHS token at a
252 // higher level, we will assume that this matches the unbalanced token
253 // and return it. Otherwise, this is a spurious RHS token, which we skip.
254 case tok::r_paren:
255 if (ParenCount && !isFirstTokenConsumed)
256 return false; // Matches something.
257 Toks.push_back(Tok);
258 ConsumeParen();
259 break;
260 case tok::r_square:
261 if (BracketCount && !isFirstTokenConsumed)
262 return false; // Matches something.
263 Toks.push_back(Tok);
264 ConsumeBracket();
265 break;
266 case tok::r_brace:
267 if (BraceCount && !isFirstTokenConsumed)
268 return false; // Matches something.
269 Toks.push_back(Tok);
270 ConsumeBrace();
271 break;
272
273 case tok::string_literal:
274 case tok::wide_string_literal:
275 Toks.push_back(Tok);
276 ConsumeStringToken();
277 break;
278 default:
279 // consume this token.
280 Toks.push_back(Tok);
281 ConsumeToken();
282 break;
283 }
284 isFirstTokenConsumed = false;
285 }
286}