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