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