Amazing that there are still issues with the fields of anonymous struct/unions..
[clang.git] / lib / Parse / ParseCXXInlineMethods.cpp
blobd62e71836fa263add3490b9f7d4db48d03a4581f
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.
12 //===----------------------------------------------------------------------===//
14 #include "clang/Parse/ParseDiagnostic.h"
15 #include "clang/Parse/Parser.h"
16 #include "clang/Sema/DeclSpec.h"
17 #include "clang/Sema/Scope.h"
18 using namespace clang;
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.
23 Decl *Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
24 const ParsedTemplateInfo &TemplateInfo,
25 const VirtSpecifiers& VS) {
26 assert(D.isFunctionDeclarator() && "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'!");
30 MultiTemplateParamsArg TemplateParams(Actions,
31 TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->data() : 0,
32 TemplateInfo.TemplateParams ? TemplateInfo.TemplateParams->size() : 0);
34 Decl *FnD;
35 if (D.getDeclSpec().isFriendSpecified())
36 // FIXME: Friend templates
37 FnD = Actions.ActOnFriendFunctionDecl(getCurScope(), D, true,
38 move(TemplateParams));
39 else { // FIXME: pass template information through
40 if (VS.isOverrideSpecified())
41 Diag(VS.getOverrideLoc(), diag::ext_override_inline) << "override";
42 if (VS.isFinalSpecified())
43 Diag(VS.getFinalLoc(), diag::ext_override_inline) << "final";
44 if (VS.isNewSpecified())
45 Diag(VS.getNewLoc(), diag::ext_override_inline) << "new";
47 FnD = Actions.ActOnCXXMemberDeclarator(getCurScope(), AS, D,
48 move(TemplateParams), 0,
49 VS, 0, /*IsDefinition*/true);
52 HandleMemberFunctionDefaultArgs(D, FnD);
54 // Consume the tokens and store them for later parsing.
56 LexedMethod* LM = new LexedMethod(this, FnD);
57 getCurrentClass().LateParsedDeclarations.push_back(LM);
58 LM->TemplateScope = getCurScope()->isTemplateParamScope();
59 CachedTokens &Toks = LM->Toks;
61 tok::TokenKind kind = Tok.getKind();
62 // We may have a constructor initializer or function-try-block here.
63 if (kind == tok::colon || kind == tok::kw_try) {
64 // Consume everything up to (and including) the left brace.
65 if (!ConsumeAndStoreUntil(tok::l_brace, Toks)) {
66 // We didn't find the left-brace we expected after the
67 // constructor initializer.
68 if (Tok.is(tok::semi)) {
69 // We found a semicolon; complain, consume the semicolon, and
70 // don't try to parse this method later.
71 Diag(Tok.getLocation(), diag::err_expected_lbrace);
72 ConsumeAnyToken();
73 delete getCurrentClass().LateParsedDeclarations.back();
74 getCurrentClass().LateParsedDeclarations.pop_back();
75 return FnD;
79 } else {
80 // Begin by storing the '{' token.
81 Toks.push_back(Tok);
82 ConsumeBrace();
84 // Consume everything up to (and including) the matching right brace.
85 ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
87 // If we're in a function-try-block, we need to store all the catch blocks.
88 if (kind == tok::kw_try) {
89 while (Tok.is(tok::kw_catch)) {
90 ConsumeAndStoreUntil(tok::l_brace, Toks, /*StopAtSemi=*/false);
91 ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
95 return FnD;
98 Parser::LateParsedDeclaration::~LateParsedDeclaration() {}
99 void Parser::LateParsedDeclaration::ParseLexedMethodDeclarations() {}
100 void Parser::LateParsedDeclaration::ParseLexedMethodDefs() {}
102 Parser::LateParsedClass::LateParsedClass(Parser *P, ParsingClass *C)
103 : Self(P), Class(C) {}
105 Parser::LateParsedClass::~LateParsedClass() {
106 Self->DeallocateParsedClasses(Class);
109 void Parser::LateParsedClass::ParseLexedMethodDeclarations() {
110 Self->ParseLexedMethodDeclarations(*Class);
113 void Parser::LateParsedClass::ParseLexedMethodDefs() {
114 Self->ParseLexedMethodDefs(*Class);
117 void Parser::LateParsedMethodDeclaration::ParseLexedMethodDeclarations() {
118 Self->ParseLexedMethodDeclaration(*this);
121 void Parser::LexedMethod::ParseLexedMethodDefs() {
122 Self->ParseLexedMethodDef(*this);
125 /// ParseLexedMethodDeclarations - We finished parsing the member
126 /// specification of a top (non-nested) C++ class. Now go over the
127 /// stack of method declarations with some parts for which parsing was
128 /// delayed (such as default arguments) and parse them.
129 void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
130 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
131 ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
132 if (HasTemplateScope)
133 Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
135 // The current scope is still active if we're the top-level class.
136 // Otherwise we'll need to push and enter a new scope.
137 bool HasClassScope = !Class.TopLevelClass;
138 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
139 HasClassScope);
140 if (HasClassScope)
141 Actions.ActOnStartDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate);
143 for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
144 Class.LateParsedDeclarations[i]->ParseLexedMethodDeclarations();
147 if (HasClassScope)
148 Actions.ActOnFinishDelayedMemberDeclarations(getCurScope(), Class.TagOrTemplate);
151 void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
152 // If this is a member template, introduce the template parameter scope.
153 ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
154 if (LM.TemplateScope)
155 Actions.ActOnReenterTemplateScope(getCurScope(), LM.Method);
157 // Start the delayed C++ method declaration
158 Actions.ActOnStartDelayedCXXMethodDeclaration(getCurScope(), LM.Method);
160 // Introduce the parameters into scope and parse their default
161 // arguments.
162 ParseScope PrototypeScope(this,
163 Scope::FunctionPrototypeScope|Scope::DeclScope);
164 for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
165 // Introduce the parameter into scope.
166 Actions.ActOnDelayedCXXMethodParameter(getCurScope(), LM.DefaultArgs[I].Param);
168 if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
169 // Save the current token position.
170 SourceLocation origLoc = Tok.getLocation();
172 // Parse the default argument from its saved token stream.
173 Toks->push_back(Tok); // So that the current token doesn't get lost
174 PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
176 // Consume the previously-pushed token.
177 ConsumeAnyToken();
179 // Consume the '='.
180 assert(Tok.is(tok::equal) && "Default argument not starting with '='");
181 SourceLocation EqualLoc = ConsumeToken();
183 // The argument isn't actually potentially evaluated unless it is
184 // used.
185 EnterExpressionEvaluationContext Eval(Actions,
186 Sema::PotentiallyEvaluatedIfUsed);
188 ExprResult DefArgResult(ParseAssignmentExpression());
189 if (DefArgResult.isInvalid())
190 Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
191 else {
192 if (Tok.is(tok::cxx_defaultarg_end))
193 ConsumeToken();
194 else
195 Diag(Tok.getLocation(), diag::err_default_arg_unparsed);
196 Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
197 DefArgResult.take());
200 assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
201 Tok.getLocation()) &&
202 "ParseAssignmentExpression went over the default arg tokens!");
203 // There could be leftover tokens (e.g. because of an error).
204 // Skip through until we reach the original token position.
205 while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
206 ConsumeAnyToken();
208 delete Toks;
209 LM.DefaultArgs[I].Toks = 0;
212 PrototypeScope.Exit();
214 // Finish the delayed C++ method declaration.
215 Actions.ActOnFinishDelayedCXXMethodDeclaration(getCurScope(), LM.Method);
218 /// ParseLexedMethodDefs - We finished parsing the member specification of a top
219 /// (non-nested) C++ class. Now go over the stack of lexed methods that were
220 /// collected during its parsing and parse them all.
221 void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
222 bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
223 ParseScope ClassTemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
224 if (HasTemplateScope)
225 Actions.ActOnReenterTemplateScope(getCurScope(), Class.TagOrTemplate);
227 bool HasClassScope = !Class.TopLevelClass;
228 ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
229 HasClassScope);
231 for (size_t i = 0; i < Class.LateParsedDeclarations.size(); ++i) {
232 Class.LateParsedDeclarations[i]->ParseLexedMethodDefs();
236 void Parser::ParseLexedMethodDef(LexedMethod &LM) {
237 // If this is a member template, introduce the template parameter scope.
238 ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
239 if (LM.TemplateScope)
240 Actions.ActOnReenterTemplateScope(getCurScope(), LM.D);
242 // Save the current token position.
243 SourceLocation origLoc = Tok.getLocation();
245 assert(!LM.Toks.empty() && "Empty body!");
246 // Append the current token at the end of the new token stream so that it
247 // doesn't get lost.
248 LM.Toks.push_back(Tok);
249 PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
251 // Consume the previously pushed token.
252 ConsumeAnyToken();
253 assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
254 && "Inline method not starting with '{', ':' or 'try'");
256 // Parse the method body. Function body parsing code is similar enough
257 // to be re-used for method bodies as well.
258 ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
259 Actions.ActOnStartOfFunctionDef(getCurScope(), LM.D);
261 if (Tok.is(tok::kw_try)) {
262 ParseFunctionTryBlock(LM.D);
263 assert(!PP.getSourceManager().isBeforeInTranslationUnit(origLoc,
264 Tok.getLocation()) &&
265 "ParseFunctionTryBlock went over the cached tokens!");
266 // There could be leftover tokens (e.g. because of an error).
267 // Skip through until we reach the original token position.
268 while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
269 ConsumeAnyToken();
270 return;
272 if (Tok.is(tok::colon)) {
273 ParseConstructorInitializer(LM.D);
275 // Error recovery.
276 if (!Tok.is(tok::l_brace)) {
277 Actions.ActOnFinishFunctionBody(LM.D, 0);
278 return;
280 } else
281 Actions.ActOnDefaultCtorInitializers(LM.D);
283 ParseFunctionStatementBody(LM.D);
285 if (Tok.getLocation() != origLoc) {
286 // Due to parsing error, we either went over the cached tokens or
287 // there are still cached tokens left. If it's the latter case skip the
288 // leftover tokens.
289 // Since this is an uncommon situation that should be avoided, use the
290 // expensive isBeforeInTranslationUnit call.
291 if (PP.getSourceManager().isBeforeInTranslationUnit(Tok.getLocation(),
292 origLoc))
293 while (Tok.getLocation() != origLoc && Tok.isNot(tok::eof))
294 ConsumeAnyToken();
299 /// ConsumeAndStoreUntil - Consume and store the token at the passed token
300 /// container until the token 'T' is reached (which gets
301 /// consumed/stored too, if ConsumeFinalToken).
302 /// If StopAtSemi is true, then we will stop early at a ';' character.
303 /// Returns true if token 'T1' or 'T2' was found.
304 /// NOTE: This is a specialized version of Parser::SkipUntil.
305 bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
306 CachedTokens &Toks,
307 bool StopAtSemi, bool ConsumeFinalToken) {
308 // We always want this function to consume at least one token if the first
309 // token isn't T and if not at EOF.
310 bool isFirstTokenConsumed = true;
311 while (1) {
312 // If we found one of the tokens, stop and return true.
313 if (Tok.is(T1) || Tok.is(T2)) {
314 if (ConsumeFinalToken) {
315 Toks.push_back(Tok);
316 ConsumeAnyToken();
318 return true;
321 switch (Tok.getKind()) {
322 case tok::eof:
323 // Ran out of tokens.
324 return false;
326 case tok::l_paren:
327 // Recursively consume properly-nested parens.
328 Toks.push_back(Tok);
329 ConsumeParen();
330 ConsumeAndStoreUntil(tok::r_paren, Toks, /*StopAtSemi=*/false);
331 break;
332 case tok::l_square:
333 // Recursively consume properly-nested square brackets.
334 Toks.push_back(Tok);
335 ConsumeBracket();
336 ConsumeAndStoreUntil(tok::r_square, Toks, /*StopAtSemi=*/false);
337 break;
338 case tok::l_brace:
339 // Recursively consume properly-nested braces.
340 Toks.push_back(Tok);
341 ConsumeBrace();
342 ConsumeAndStoreUntil(tok::r_brace, Toks, /*StopAtSemi=*/false);
343 break;
345 // Okay, we found a ']' or '}' or ')', which we think should be balanced.
346 // Since the user wasn't looking for this token (if they were, it would
347 // already be handled), this isn't balanced. If there is a LHS token at a
348 // higher level, we will assume that this matches the unbalanced token
349 // and return it. Otherwise, this is a spurious RHS token, which we skip.
350 case tok::r_paren:
351 if (ParenCount && !isFirstTokenConsumed)
352 return false; // Matches something.
353 Toks.push_back(Tok);
354 ConsumeParen();
355 break;
356 case tok::r_square:
357 if (BracketCount && !isFirstTokenConsumed)
358 return false; // Matches something.
359 Toks.push_back(Tok);
360 ConsumeBracket();
361 break;
362 case tok::r_brace:
363 if (BraceCount && !isFirstTokenConsumed)
364 return false; // Matches something.
365 Toks.push_back(Tok);
366 ConsumeBrace();
367 break;
369 case tok::string_literal:
370 case tok::wide_string_literal:
371 Toks.push_back(Tok);
372 ConsumeStringToken();
373 break;
374 case tok::semi:
375 if (StopAtSemi)
376 return false;
377 // FALL THROUGH.
378 default:
379 // consume this token.
380 Toks.push_back(Tok);
381 ConsumeToken();
382 break;
384 isFirstTokenConsumed = false;