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"
18 using 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.
23 Parser::DeclPtrTy
24 Parser::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.
79 void 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.
141 void 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.
194 bool 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