 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
80.5% |
231 / 287 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
97.9% |
281 / 287 |
| |
|
Line Coverage: |
89.1% |
237 / 266 |
| |
 |
|
 |
1 : //===--- ParseTentative.cpp - Ambiguity Resolution 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 the tentative parsing portions of the Parser
11 : // interfaces, for ambiguity resolution.
12 : //
13 : //===----------------------------------------------------------------------===//
14 :
15 : #include "clang/Parse/Parser.h"
16 : #include "clang/Parse/ParseDiagnostic.h"
17 : using namespace clang;
18 :
19 : /// isCXXDeclarationStatement - C++-specialized function that disambiguates
20 : /// between a declaration or an expression statement, when parsing function
21 : /// bodies. Returns true for declaration, false for expression.
22 : ///
23 : /// declaration-statement:
24 : /// block-declaration
25 : ///
26 : /// block-declaration:
27 : /// simple-declaration
28 : /// asm-definition
29 : /// namespace-alias-definition
30 : /// using-declaration
31 : /// using-directive
32 : /// [C++0x] static_assert-declaration
33 : ///
34 : /// asm-definition:
35 : /// 'asm' '(' string-literal ')' ';'
36 : ///
37 : /// namespace-alias-definition:
38 : /// 'namespace' identifier = qualified-namespace-specifier ';'
39 : ///
40 : /// using-declaration:
41 : /// 'using' typename[opt] '::'[opt] nested-name-specifier
42 : /// unqualified-id ';'
43 : /// 'using' '::' unqualified-id ;
44 : ///
45 : /// using-directive:
46 : /// 'using' 'namespace' '::'[opt] nested-name-specifier[opt]
47 : /// namespace-name ';'
48 : ///
49 4968: bool Parser::isCXXDeclarationStatement() {
43: branch 1 taken
4925: branch 2 taken
50 4968: switch (Tok.getKind()) {
51 : // asm-definition
52 : case tok::kw_asm:
53 : // namespace-alias-definition
54 : case tok::kw_namespace:
55 : // using-declaration
56 : // using-directive
57 : case tok::kw_using:
58 : // static_assert-declaration
59 : case tok::kw_static_assert:
60 43: return true;
61 : // simple-declaration
62 : default:
63 4925: return isCXXSimpleDeclaration();
64 : }
65 : }
66 :
67 : /// isCXXSimpleDeclaration - C++-specialized function that disambiguates
68 : /// between a simple-declaration or an expression-statement.
69 : /// If during the disambiguation process a parsing error is encountered,
70 : /// the function returns true to let the declaration parsing code handle it.
71 : /// Returns false if the statement is disambiguated as expression.
72 : ///
73 : /// simple-declaration:
74 : /// decl-specifier-seq init-declarator-list[opt] ';'
75 : ///
76 4985: bool Parser::isCXXSimpleDeclaration() {
77 : // C++ 6.8p1:
78 : // There is an ambiguity in the grammar involving expression-statements and
79 : // declarations: An expression-statement with a function-style explicit type
80 : // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
81 : // from a declaration where the first declarator starts with a '('. In those
82 : // cases the statement is a declaration. [Note: To disambiguate, the whole
83 : // statement might have to be examined to determine if it is an
84 : // expression-statement or a declaration].
85 :
86 : // C++ 6.8p3:
87 : // The disambiguation is purely syntactic; that is, the meaning of the names
88 : // occurring in such a statement, beyond whether they are type-names or not,
89 : // is not generally used in or changed by the disambiguation. Class
90 : // templates are instantiated as necessary to determine if a qualified name
91 : // is a type-name. Disambiguation precedes parsing, and a statement
92 : // disambiguated as a declaration may be an ill-formed declaration.
93 :
94 : // We don't have to parse all of the decl-specifier-seq part. There's only
95 : // an ambiguity if the first decl-specifier is
96 : // simple-type-specifier/typename-specifier followed by a '(', which may
97 : // indicate a function-style cast expression.
98 : // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
99 : // a case.
100 :
101 4985: TPResult TPR = isCXXDeclarationSpecifier();
4822: branch 2 taken
163: branch 3 taken
102 4985: if (TPR != TPResult::Ambiguous())
103 4822: return TPR != TPResult::False(); // Returns true for TPResult::True() or
104 : // TPResult::Error().
105 :
106 : // FIXME: Add statistics about the number of ambiguous statements encountered
107 : // and how they were resolved (number of declarations+number of expressions).
108 :
109 : // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
110 : // We need tentative parsing...
111 :
112 163: TentativeParsingAction PA(*this);
113 :
114 163: TPR = TryParseSimpleDeclaration();
115 163: SourceLocation TentativeParseLoc = Tok.getLocation();
116 :
117 163: PA.Revert();
118 :
119 : // In case of an error, let the declaration parsing code handle it.
0: branch 2 not taken
163: branch 3 taken
120 163: if (TPR == TPResult::Error())
121 0: return true;
122 :
123 : // Declarations take precedence over expressions.
122: branch 2 taken
41: branch 3 taken
124 163: if (TPR == TPResult::Ambiguous())
125 122: TPR = TPResult::True();
126 :
38: branch 2 taken
125: branch 3 taken
0: branch 6 not taken
38: branch 7 taken
127 163: assert(TPR == TPResult::True() || TPR == TPResult::False());
128 163: return TPR == TPResult::True();
129 : }
130 :
131 : /// simple-declaration:
132 : /// decl-specifier-seq init-declarator-list[opt] ';'
133 : ///
134 163: Parser::TPResult Parser::TryParseSimpleDeclaration() {
135 : // We know that we have a simple-type-specifier/typename-specifier followed
136 : // by a '('.
0: branch 3 not taken
163: branch 4 taken
137 163: assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
138 :
2: branch 1 taken
161: branch 2 taken
139 163: if (Tok.is(tok::kw_typeof))
140 2: TryParseTypeofSpecifier();
141 : else
142 161: ConsumeToken();
143 :
163: branch 1 taken
0: branch 2 not taken
144 163: assert(Tok.is(tok::l_paren) && "Expected '('");
145 :
146 163: TPResult TPR = TryParseInitDeclaratorList();
37: branch 2 taken
126: branch 3 taken
147 163: if (TPR != TPResult::Ambiguous())
148 37: return TPR;
149 :
4: branch 1 taken
122: branch 2 taken
150 126: if (Tok.isNot(tok::semi))
151 4: return TPResult::False();
152 :
153 122: return TPResult::Ambiguous();
154 : }
155 :
156 : /// init-declarator-list:
157 : /// init-declarator
158 : /// init-declarator-list ',' init-declarator
159 : ///
160 : /// init-declarator:
161 : /// declarator initializer[opt]
162 : /// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
163 : ///
164 : /// initializer:
165 : /// '=' initializer-clause
166 : /// '(' expression-list ')'
167 : ///
168 : /// initializer-clause:
169 : /// assignment-expression
170 : /// '{' initializer-list ','[opt] '}'
171 : /// '{' '}'
172 : ///
173 164: Parser::TPResult Parser::TryParseInitDeclaratorList() {
174 : // GCC only examines the first declarator for disambiguation:
175 : // i.e:
176 : // int(x), ++x; // GCC regards it as ill-formed declaration.
177 : //
178 : // Comeau and MSVC will regard the above statement as correct expression.
179 : // Clang examines all of the declarators and also regards the above statement
180 : // as correct expression.
181 :
182 1: while (1) {
183 : // declarator
184 164: TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
34: branch 2 taken
130: branch 3 taken
185 164: if (TPR != TPResult::Ambiguous())
186 34: return TPR;
187 :
188 : // [GNU] simple-asm-expr[opt] attributes[opt]
130: branch 1 taken
0: branch 2 not taken
3: branch 4 taken
127: branch 5 taken
3: branch 6 taken
127: branch 7 taken
189 130: if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
190 3: return TPResult::True();
191 :
192 : // initializer[opt]
1: branch 1 taken
126: branch 2 taken
193 127: if (Tok.is(tok::l_paren)) {
194 : // Parse through the parens.
195 1: ConsumeParen();
0: branch 1 not taken
1: branch 2 taken
196 1: if (!SkipUntil(tok::r_paren))
197 0: return TPResult::Error();
111: branch 1 taken
15: branch 2 taken
198 126: } else if (Tok.is(tok::equal)) {
199 : // MSVC won't examine the rest of declarators if '=' is encountered, it
200 : // will conclude that it is a declaration.
201 : // Comeau and Clang will examine the rest of declarators.
202 : // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
203 : // expression.
204 : //
205 : // Parse through the initializer-clause.
206 111: SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
207 : }
208 :
1: branch 1 taken
126: branch 2 taken
209 127: if (Tok.isNot(tok::comma))
210 126: break;
211 1: ConsumeToken(); // the comma.
212 : }
213 :
214 126: return TPResult::Ambiguous();
215 : }
216 :
217 : /// isCXXConditionDeclaration - Disambiguates between a declaration or an
218 : /// expression for a condition of a if/switch/while/for statement.
219 : /// If during the disambiguation process a parsing error is encountered,
220 : /// the function returns true to let the declaration parsing code handle it.
221 : ///
222 : /// condition:
223 : /// expression
224 : /// type-specifier-seq declarator '=' assignment-expression
225 : /// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
226 : /// '=' assignment-expression
227 : ///
228 365: bool Parser::isCXXConditionDeclaration() {
229 365: TPResult TPR = isCXXDeclarationSpecifier();
352: branch 2 taken
13: branch 3 taken
230 365: if (TPR != TPResult::Ambiguous())
231 352: return TPR != TPResult::False(); // Returns true for TPResult::True() or
232 : // TPResult::Error().
233 :
234 : // FIXME: Add statistics about the number of ambiguous statements encountered
235 : // and how they were resolved (number of declarations+number of expressions).
236 :
237 : // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
238 : // We need tentative parsing...
239 :
240 13: TentativeParsingAction PA(*this);
241 :
242 : // type-specifier-seq
0: branch 1 not taken
13: branch 2 taken
243 13: if (Tok.is(tok::kw_typeof))
244 0: TryParseTypeofSpecifier();
245 : else
246 13: ConsumeToken();
13: branch 1 taken
0: branch 2 not taken
247 13: assert(Tok.is(tok::l_paren) && "Expected '('");
248 :
249 : // declarator
250 13: TPR = TryParseDeclarator(false/*mayBeAbstract*/);
251 :
252 : // In case of an error, let the declaration parsing code handle it.
0: branch 2 not taken
13: branch 3 taken
253 13: if (TPR == TPResult::Error())
254 0: TPR = TPResult::True();
255 :
2: branch 2 taken
11: branch 3 taken
256 13: if (TPR == TPResult::Ambiguous()) {
257 : // '='
258 : // [GNU] simple-asm-expr[opt] attributes[opt]
1: branch 1 taken
1: branch 2 taken
1: branch 4 taken
0: branch 5 not taken
0: branch 7 not taken
1: branch 8 taken
1: branch 9 taken
1: branch 10 taken
259 2: if (Tok.is(tok::equal) ||
260 : Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
261 1: TPR = TPResult::True();
262 : else
263 1: TPR = TPResult::False();
264 : }
265 :
266 13: PA.Revert();
267 :
12: branch 2 taken
1: branch 3 taken
0: branch 6 not taken
12: branch 7 taken
268 13: assert(TPR == TPResult::True() || TPR == TPResult::False());
269 13: return TPR == TPResult::True();
270 : }
271 :
272 : /// \brief Determine whether the next set of tokens contains a type-id.
273 : ///
274 : /// The context parameter states what context we're parsing right
275 : /// now, which affects how this routine copes with the token
276 : /// following the type-id. If the context is TypeIdInParens, we have
277 : /// already parsed the '(' and we will cease lookahead when we hit
278 : /// the corresponding ')'. If the context is
279 : /// TypeIdAsTemplateArgument, we've already parsed the '<' or ','
280 : /// before this template argument, and will cease lookahead when we
281 : /// hit a '>', '>>' (in C++0x), or ','. Returns true for a type-id
282 : /// and false for an expression. If during the disambiguation
283 : /// process a parsing error is encountered, the function returns
284 : /// true to let the declaration parsing code handle it.
285 : ///
286 : /// type-id:
287 : /// type-specifier-seq abstract-declarator[opt]
288 : ///
289 6392: bool Parser::isCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous) {
290 :
291 6392: isAmbiguous = false;
292 :
293 : // C++ 8.2p2:
294 : // The ambiguity arising from the similarity between a function-style cast and
295 : // a type-id can occur in different contexts. The ambiguity appears as a
296 : // choice between a function-style cast expression and a declaration of a
297 : // type. The resolution is that any construct that could possibly be a type-id
298 : // in its syntactic context shall be considered a type-id.
299 :
300 6392: TPResult TPR = isCXXDeclarationSpecifier();
6209: branch 2 taken
183: branch 3 taken
301 6392: if (TPR != TPResult::Ambiguous())
302 6209: return TPR != TPResult::False(); // Returns true for TPResult::True() or
303 : // TPResult::Error().
304 :
305 : // FIXME: Add statistics about the number of ambiguous statements encountered
306 : // and how they were resolved (number of declarations+number of expressions).
307 :
308 : // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
309 : // We need tentative parsing...
310 :
311 183: TentativeParsingAction PA(*this);
312 :
313 : // type-specifier-seq
0: branch 1 not taken
183: branch 2 taken
314 183: if (Tok.is(tok::kw_typeof))
315 0: TryParseTypeofSpecifier();
316 : else
317 183: ConsumeToken();
183: branch 1 taken
0: branch 2 not taken
318 183: assert(Tok.is(tok::l_paren) && "Expected '('");
319 :
320 : // declarator
321 183: TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
322 :
323 : // In case of an error, let the declaration parsing code handle it.
0: branch 2 not taken
183: branch 3 taken
324 183: if (TPR == TPResult::Error())
325 0: TPR = TPResult::True();
326 :
163: branch 2 taken
20: branch 3 taken
327 183: if (TPR == TPResult::Ambiguous()) {
328 : // We are supposed to be inside parens, so if after the abstract declarator
329 : // we encounter a ')' this is a type-id, otherwise it's an expression.
84: branch 0 taken
79: branch 1 taken
75: branch 3 taken
9: branch 4 taken
75: branch 5 taken
88: branch 6 taken
330 163: if (Context == TypeIdInParens && Tok.is(tok::r_paren)) {
331 75: TPR = TPResult::True();
332 75: isAmbiguous = true;
333 :
334 : // We are supposed to be inside a template argument, so if after
335 : // the abstract declarator we encounter a '>', '>>' (in C++0x), or
336 : // ',', this is a type-id. Otherwise, it's an expression.
79: branch 0 taken
9: branch 1 taken
7: branch 3 taken
72: branch 4 taken
0: branch 6 not taken
7: branch 7 taken
0: branch 9 not taken
0: branch 10 not taken
0: branch 12 not taken
0: branch 13 not taken
79: branch 14 taken
9: branch 15 taken
337 88: } else if (Context == TypeIdAsTemplateArgument &&
338 : (Tok.is(tok::greater) || Tok.is(tok::comma) ||
339 : (getLang().CPlusPlus0x && Tok.is(tok::greatergreater)))) {
340 79: TPR = TPResult::True();
341 79: isAmbiguous = true;
342 :
343 : } else
344 9: TPR = TPResult::False();
345 : }
346 :
347 183: PA.Revert();
348 :
29: branch 2 taken
154: branch 3 taken
0: branch 6 not taken
29: branch 7 taken
349 183: assert(TPR == TPResult::True() || TPR == TPResult::False());
350 183: return TPR == TPResult::True();
351 : }
352 :
353 : /// isCXX0XAttributeSpecifier - returns true if this is a C++0x
354 : /// attribute-specifier. By default, unless in Obj-C++, only a cursory check is
355 : /// performed that will simply return true if a [[ is seen. Currently C++ has no
356 : /// syntactical ambiguities from this check, but it may inhibit error recovery.
357 : /// If CheckClosing is true, a check is made for closing ]] brackets.
358 : ///
359 : /// If given, After is set to the token after the attribute-specifier so that
360 : /// appropriate parsing decisions can be made; it is left untouched if false is
361 : /// returned.
362 : ///
363 : /// FIXME: If an error is in the closing ]] brackets, the program assumes
364 : /// the absence of an attribute-specifier, which can cause very yucky errors
365 : /// to occur.
366 : ///
367 : /// [C++0x] attribute-specifier:
368 : /// '[' '[' attribute-list ']' ']'
369 : ///
370 : /// [C++0x] attribute-list:
371 : /// attribute[opt]
372 : /// attribute-list ',' attribute[opt]
373 : ///
374 : /// [C++0x] attribute:
375 : /// attribute-token attribute-argument-clause[opt]
376 : ///
377 : /// [C++0x] attribute-token:
378 : /// identifier
379 : /// attribute-scoped-token
380 : ///
381 : /// [C++0x] attribute-scoped-token:
382 : /// attribute-namespace '::' identifier
383 : ///
384 : /// [C++0x] attribute-namespace:
385 : /// identifier
386 : ///
387 : /// [C++0x] attribute-argument-clause:
388 : /// '(' balanced-token-seq ')'
389 : ///
390 : /// [C++0x] balanced-token-seq:
391 : /// balanced-token
392 : /// balanced-token-seq balanced-token
393 : ///
394 : /// [C++0x] balanced-token:
395 : /// '(' balanced-token-seq ')'
396 : /// '[' balanced-token-seq ']'
397 : /// '{' balanced-token-seq '}'
398 : /// any token but '(', ')', '[', ']', '{', or '}'
399 : bool Parser::isCXX0XAttributeSpecifier (bool CheckClosing,
400 27929: tok::TokenKind *After) {
800: branch 1 taken
27129: branch 2 taken
749: branch 5 taken
51: branch 6 taken
27878: branch 7 taken
51: branch 8 taken
401 27929: if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
402 27878: return false;
403 :
404 : // No tentative parsing if we don't need to look for ]]
38: branch 0 taken
13: branch 1 taken
38: branch 3 taken
0: branch 4 not taken
38: branch 5 taken
13: branch 6 taken
405 51: if (!CheckClosing && !getLang().ObjC1)
406 38: return true;
407 :
408 : struct TentativeReverter {
409 : TentativeParsingAction PA;
410 :
411 13: TentativeReverter (Parser& P)
412 13: : PA(P)
413 13: {}
414 13: ~TentativeReverter () {
415 13: PA.Revert();
416 13: }
417 13: } R(*this);
418 :
419 : // Opening brackets were checked for above.
420 13: ConsumeBracket();
421 13: ConsumeBracket();
422 :
423 : // SkipUntil will handle balanced tokens, which are guaranteed in attributes.
424 13: SkipUntil(tok::r_square, false);
425 :
0: branch 1 not taken
13: branch 2 taken
426 13: if (Tok.isNot(tok::r_square))
427 0: return false;
428 13: ConsumeBracket();
429 :
0: branch 0 not taken
13: branch 1 taken
430 13: if (After)
431 0: *After = Tok.getKind();
432 :
433 13: return true;
434 : }
435 :
436 : /// declarator:
437 : /// direct-declarator
438 : /// ptr-operator declarator
439 : ///
440 : /// direct-declarator:
441 : /// declarator-id
442 : /// direct-declarator '(' parameter-declaration-clause ')'
443 : /// cv-qualifier-seq[opt] exception-specification[opt]
444 : /// direct-declarator '[' constant-expression[opt] ']'
445 : /// '(' declarator ')'
446 : /// [GNU] '(' attributes declarator ')'
447 : ///
448 : /// abstract-declarator:
449 : /// ptr-operator abstract-declarator[opt]
450 : /// direct-abstract-declarator
451 : ///
452 : /// direct-abstract-declarator:
453 : /// direct-abstract-declarator[opt]
454 : /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
455 : /// exception-specification[opt]
456 : /// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
457 : /// '(' abstract-declarator ')'
458 : ///
459 : /// ptr-operator:
460 : /// '*' cv-qualifier-seq[opt]
461 : /// '&'
462 : /// [C++0x] '&&' [TODO]
463 : /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt]
464 : ///
465 : /// cv-qualifier-seq:
466 : /// cv-qualifier cv-qualifier-seq[opt]
467 : ///
468 : /// cv-qualifier:
469 : /// 'const'
470 : /// 'volatile'
471 : ///
472 : /// declarator-id:
473 : /// id-expression
474 : ///
475 : /// id-expression:
476 : /// unqualified-id
477 : /// qualified-id [TODO]
478 : ///
479 : /// unqualified-id:
480 : /// identifier
481 : /// operator-function-id [TODO]
482 : /// conversion-function-id [TODO]
483 : /// '~' class-name [TODO]
484 : /// template-id [TODO]
485 : ///
486 : Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
487 1228: bool mayHaveIdentifier) {
488 : // declarator:
489 : // direct-declarator
490 : // ptr-operator declarator
491 :
492 381: while (1) {
1225: branch 1 taken
3: branch 2 taken
243: branch 4 taken
982: branch 5 taken
246: branch 6 taken
982: branch 7 taken
493 1228: if (Tok.is(tok::coloncolon) || Tok.is(tok::identifier))
494 246: TryAnnotateCXXScopeToken(true);
495 :
1000: branch 1 taken
228: branch 2 taken
965: branch 4 taken
35: branch 5 taken
927: branch 7 taken
38: branch 8 taken
89: branch 10 taken
838: branch 11 taken
80: branch 14 taken
9: branch 15 taken
381: branch 16 taken
847: branch 17 taken
496 1228: if (Tok.is(tok::star) || Tok.is(tok::amp) || Tok.is(tok::caret) ||
497 : (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::star))) {
498 : // ptr-operator
499 381: ConsumeToken();
381: branch 1 taken
2: branch 2 taken
381: branch 4 taken
0: branch 5 not taken
0: branch 7 not taken
381: branch 8 taken
2: branch 9 taken
381: branch 10 taken
500 764: while (Tok.is(tok::kw_const) ||
501 : Tok.is(tok::kw_volatile) ||
502 : Tok.is(tok::kw_restrict))
503 2: ConsumeToken();
504 : } else {
505 847: break;
506 : }
507 : }
508 :
509 : // direct-declarator:
510 : // direct-abstract-declarator:
511 :
650: branch 1 taken
197: branch 2 taken
9: branch 4 taken
641: branch 5 taken
8: branch 8 taken
1: branch 9 taken
194: branch 10 taken
11: branch 11 taken
194: branch 12 taken
653: branch 13 taken
512 847: if ((Tok.is(tok::identifier) ||
513 : (Tok.is(tok::annot_cxxscope) && NextToken().is(tok::identifier))) &&
514 : mayHaveIdentifier) {
515 : // declarator-id
7: branch 1 taken
187: branch 2 taken
516 194: if (Tok.is(tok::annot_cxxscope))
517 7: ConsumeToken();
518 194: ConsumeToken();
466: branch 1 taken
187: branch 2 taken
519 653: } else if (Tok.is(tok::l_paren)) {
520 466: ConsumeParen();
281: branch 0 taken
185: branch 1 taken
233: branch 3 taken
48: branch 4 taken
232: branch 6 taken
1: branch 7 taken
28: branch 9 taken
204: branch 10 taken
77: branch 11 taken
389: branch 12 taken
521 466: if (mayBeAbstract &&
522 : (Tok.is(tok::r_paren) || // 'int()' is a function.
523 : Tok.is(tok::ellipsis) || // 'int(...)' is a function.
524 : isDeclarationSpecifier())) { // 'int(int)' is a function.
525 : // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
526 : // exception-specification[opt]
527 77: TPResult TPR = TryParseFunctionDeclarator();
0: branch 2 not taken
77: branch 3 taken
528 77: if (TPR != TPResult::Ambiguous())
529 0: return TPR;
530 : } else {
531 : // '(' declarator ')'
532 : // '(' attributes declarator ')'
533 : // '(' abstract-declarator ')'
0: branch 1 not taken
389: branch 2 taken
534 389: if (Tok.is(tok::kw___attribute))
535 0: return TPResult::True(); // attributes indicate declaration
536 389: TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
37: branch 2 taken
352: branch 3 taken
537 389: if (TPR != TPResult::Ambiguous())
538 37: return TPR;
27: branch 1 taken
325: branch 2 taken
539 352: if (Tok.isNot(tok::r_paren))
540 27: return TPResult::False();
541 325: ConsumeParen();
542 : }
38: branch 0 taken
149: branch 1 taken
543 187: } else if (!mayBeAbstract) {
544 38: return TPResult::False();
545 : }
546 :
547 298: while (1) {
548 1043: TPResult TPR(TPResult::Ambiguous());
549 :
256: branch 1 taken
787: branch 2 taken
550 1043: if (Tok.is(tok::l_paren)) {
551 : // Check whether we have a function declarator or a possible ctor-style
552 : // initializer that follows the declarator. Note that ctor-style
553 : // initializers are not possible in contexts where abstract declarators
554 : // are allowed.
115: branch 0 taken
141: branch 1 taken
1: branch 3 taken
114: branch 4 taken
255: branch 5 taken
1: branch 6 taken
555 256: if (!mayBeAbstract && !isCXXFunctionDeclarator(false/*warnIfAmbiguous*/))
556 1: break;
557 :
558 : // direct-declarator '(' parameter-declaration-clause ')'
559 : // cv-qualifier-seq[opt] exception-specification[opt]
560 255: ConsumeParen();
561 255: TPR = TryParseFunctionDeclarator();
744: branch 1 taken
43: branch 2 taken
562 787: } else if (Tok.is(tok::l_square)) {
563 : // direct-declarator '[' constant-expression[opt] ']'
564 : // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
565 43: TPR = TryParseBracketDeclarator();
566 : } else {
567 744: break;
568 : }
569 :
0: branch 2 not taken
298: branch 3 taken
570 298: if (TPR != TPResult::Ambiguous())
571 0: return TPR;
572 : }
573 :
574 745: return TPResult::Ambiguous();
575 : }
576 :
577 : /// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
578 : /// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
579 : /// be either a decl-specifier or a function-style cast, and TPResult::Error()
580 : /// if a parsing error was found and reported.
581 : ///
582 : /// decl-specifier:
583 : /// storage-class-specifier
584 : /// type-specifier
585 : /// function-specifier
586 : /// 'friend'
587 : /// 'typedef'
588 : /// [C++0x] 'constexpr'
589 : /// [GNU] attributes declaration-specifiers[opt]
590 : ///
591 : /// storage-class-specifier:
592 : /// 'register'
593 : /// 'static'
594 : /// 'extern'
595 : /// 'mutable'
596 : /// 'auto'
597 : /// [GNU] '__thread'
598 : ///
599 : /// function-specifier:
600 : /// 'inline'
601 : /// 'virtual'
602 : /// 'explicit'
603 : ///
604 : /// typedef-name:
605 : /// identifier
606 : ///
607 : /// type-specifier:
608 : /// simple-type-specifier
609 : /// class-specifier
610 : /// enum-specifier
611 : /// elaborated-type-specifier
612 : /// typename-specifier
613 : /// cv-qualifier
614 : ///
615 : /// simple-type-specifier:
616 : /// '::'[opt] nested-name-specifier[opt] type-name
617 : /// '::'[opt] nested-name-specifier 'template'
618 : /// simple-template-id [TODO]
619 : /// 'char'
620 : /// 'wchar_t'
621 : /// 'bool'
622 : /// 'short'
623 : /// 'int'
624 : /// 'long'
625 : /// 'signed'
626 : /// 'unsigned'
627 : /// 'float'
628 : /// 'double'
629 : /// 'void'
630 : /// [GNU] typeof-specifier
631 : /// [GNU] '_Complex'
632 : /// [C++0x] 'auto' [TODO]
633 : /// [C++0x] 'decltype' ( expression )
634 : ///
635 : /// type-name:
636 : /// class-name
637 : /// enum-name
638 : /// typedef-name
639 : ///
640 : /// elaborated-type-specifier:
641 : /// class-key '::'[opt] nested-name-specifier[opt] identifier
642 : /// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
643 : /// simple-template-id
644 : /// 'enum' '::'[opt] nested-name-specifier[opt] identifier
645 : ///
646 : /// enum-name:
647 : /// identifier
648 : ///
649 : /// enum-specifier:
650 : /// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
651 : /// 'enum' identifier[opt] '{' enumerator-list ',' '}'
652 : ///
653 : /// class-specifier:
654 : /// class-head '{' member-specification[opt] '}'
655 : ///
656 : /// class-head:
657 : /// class-key identifier[opt] base-clause[opt]
658 : /// class-key nested-name-specifier identifier base-clause[opt]
659 : /// class-key nested-name-specifier[opt] simple-template-id
660 : /// base-clause[opt]
661 : ///
662 : /// class-key:
663 : /// 'class'
664 : /// 'struct'
665 : /// 'union'
666 : ///
667 : /// cv-qualifier:
668 : /// 'const'
669 : /// 'volatile'
670 : /// [GNU] restrict
671 : ///
672 18971: Parser::TPResult Parser::isCXXDeclarationSpecifier() {
6721: branch 1 taken
33: branch 2 taken
16: branch 3 taken
737: branch 4 taken
1: branch 5 taken
10: branch 6 taken
163: branch 7 taken
9079: branch 8 taken
22: branch 9 taken
8: branch 10 taken
2181: branch 11 taken
673 18971: switch (Tok.getKind()) {
674 : case tok::identifier: // foo::bar
675 : // Check for need to substitute AltiVec __vector keyword
676 : // for "vector" identifier.
3: branch 1 taken
6718: branch 2 taken
677 6721: if (TryAltiVecVectorToken())
678 3: return TPResult::True();
679 : // Fall through.
680 : case tok::kw_typename: // typename T::type
681 : // Annotate typenames and C++ scope specifiers. If we get one, just
682 : // recurse to handle whatever we get.
4190: branch 1 taken
2561: branch 2 taken
683 6751: if (TryAnnotateTypeOrScopeToken())
684 4190: return isCXXDeclarationSpecifier();
685 : // Otherwise, not a typename.
686 2561: return TPResult::False();
687 :
688 : case tok::coloncolon: { // ::foo::bar
689 16: const Token &Next = NextToken();
16: branch 1 taken
0: branch 2 not taken
2: branch 4 taken
14: branch 5 taken
2: branch 6 taken
14: branch 7 taken
690 16: if (Next.is(tok::kw_new) || // ::new
691 : Next.is(tok::kw_delete)) // ::delete
692 2: return TPResult::False();
693 :
694 : // Annotate typenames and C++ scope specifiers. If we get one, just
695 : // recurse to handle whatever we get.
14: branch 1 taken
0: branch 2 not taken
696 14: if (TryAnnotateTypeOrScopeToken())
697 14: return isCXXDeclarationSpecifier();
698 : // Otherwise, not a typename.
699 0: return TPResult::False();
700 : }
701 :
702 : // decl-specifier:
703 : // storage-class-specifier
704 : // type-specifier
705 : // function-specifier
706 : // 'friend'
707 : // 'typedef'
708 : // 'constexpr'
709 : case tok::kw_friend:
710 : case tok::kw_typedef:
711 : case tok::kw_constexpr:
712 : // storage-class-specifier
713 : case tok::kw_register:
714 : case tok::kw_static:
715 : case tok::kw_extern:
716 : case tok::kw_mutable:
717 : case tok::kw_auto:
718 : case tok::kw___thread:
719 : // function-specifier
720 : case tok::kw_inline:
721 : case tok::kw_virtual:
722 : case tok::kw_explicit:
723 :
724 : // type-specifier:
725 : // simple-type-specifier
726 : // class-specifier
727 : // enum-specifier
728 : // elaborated-type-specifier
729 : // typename-specifier
730 : // cv-qualifier
731 :
732 : // class-specifier
733 : // elaborated-type-specifier
734 : case tok::kw_class:
735 : case tok::kw_struct:
736 : case tok::kw_union:
737 : // enum-specifier
738 : case tok::kw_enum:
739 : // cv-qualifier
740 : case tok::kw_const:
741 : case tok::kw_volatile:
742 :
743 : // GNU
744 : case tok::kw_restrict:
745 : case tok::kw__Complex:
746 : case tok::kw___attribute:
747 737: return TPResult::True();
748 :
749 : // Microsoft
750 : case tok::kw___declspec:
751 : case tok::kw___cdecl:
752 : case tok::kw___stdcall:
753 : case tok::kw___fastcall:
754 : case tok::kw___w64:
755 : case tok::kw___ptr64:
756 : case tok::kw___forceinline:
757 1: return TPResult::True();
758 :
759 : // AltiVec
760 : case tok::kw___vector:
761 10: return TPResult::True();
762 :
763 : case tok::annot_cxxscope: // foo::bar or ::foo::bar, but already parsed
764 : // We've already annotated a scope; try to annotate a type.
163: branch 1 taken
0: branch 2 not taken
155: branch 4 taken
8: branch 5 taken
155: branch 6 taken
8: branch 7 taken
765 163: if (!(TryAnnotateTypeOrScopeToken() && Tok.is(tok::annot_typename)))
766 155: return TPResult::False();
767 : // If that succeeded, fallthrough into the generic simple-type-id case.
768 :
769 : // The ambiguity resides in a simple-type-specifier/typename-specifier
770 : // followed by a '('. The '(' could either be the start of:
771 : //
772 : // direct-declarator:
773 : // '(' declarator ')'
774 : //
775 : // direct-abstract-declarator:
776 : // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
777 : // exception-specification[opt]
778 : // '(' abstract-declarator ')'
779 : //
780 : // or part of a function-style cast expression:
781 : //
782 : // simple-type-specifier '(' expression-list[opt] ')'
783 : //
784 :
785 : // simple-type-specifier:
786 :
787 : case tok::kw_char:
788 : case tok::kw_wchar_t:
789 : case tok::kw_char16_t:
790 : case tok::kw_char32_t:
791 : case tok::kw_bool:
792 : case tok::kw_short:
793 : case tok::kw_int:
794 : case tok::kw_long:
795 : case tok::kw_signed:
796 : case tok::kw_unsigned:
797 : case tok::kw_float:
798 : case tok::kw_double:
799 : case tok::kw_void:
800 : case tok::annot_typename:
616: branch 2 taken
8471: branch 3 taken
801 9087: if (NextToken().is(tok::l_paren))
802 616: return TPResult::Ambiguous();
803 :
804 8471: return TPResult::True();
805 :
806 : // GNU typeof support.
807 : case tok::kw_typeof: {
1: branch 2 taken
21: branch 3 taken
808 22: if (NextToken().isNot(tok::l_paren))
809 1: return TPResult::True();
810 :
811 21: TentativeParsingAction PA(*this);
812 :
813 21: TPResult TPR = TryParseTypeofSpecifier();
814 21: bool isFollowedByParen = Tok.is(tok::l_paren);
815 :
816 21: PA.Revert();
817 :
0: branch 2 not taken
21: branch 3 taken
818 21: if (TPR == TPResult::Error())
819 0: return TPResult::Error();
820 :
4: branch 0 taken
17: branch 1 taken
821 21: if (isFollowedByParen)
822 4: return TPResult::Ambiguous();
823 :
824 17: return TPResult::True();
825 : }
826 :
827 : // C++0x decltype support.
828 : case tok::kw_decltype:
829 8: return TPResult::True();
830 :
831 : default:
832 2181: return TPResult::False();
833 : }
834 : }
835 :
836 : /// [GNU] typeof-specifier:
837 : /// 'typeof' '(' expressions ')'
838 : /// 'typeof' '(' type-name ')'
839 : ///
840 23: Parser::TPResult Parser::TryParseTypeofSpecifier() {
23: branch 1 taken
0: branch 2 not taken
841 23: assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
842 23: ConsumeToken();
843 :
23: branch 1 taken
0: branch 2 not taken
844 23: assert(Tok.is(tok::l_paren) && "Expected '('");
845 : // Parse through the parens after 'typeof'.
846 23: ConsumeParen();
0: branch 1 not taken
23: branch 2 taken
847 23: if (!SkipUntil(tok::r_paren))
848 0: return TPResult::Error();
849 :
850 23: return TPResult::Ambiguous();
851 : }
852 :
853 2862: Parser::TPResult Parser::TryParseDeclarationSpecifier() {
854 2862: TPResult TPR = isCXXDeclarationSpecifier();
2764: branch 2 taken
98: branch 3 taken
855 2862: if (TPR != TPResult::Ambiguous())
856 2764: return TPR;
857 :
0: branch 1 not taken
98: branch 2 taken
858 98: if (Tok.is(tok::kw_typeof))
859 0: TryParseTypeofSpecifier();
860 : else
861 98: ConsumeToken();
862 :
98: branch 1 taken
0: branch 2 not taken
863 98: assert(Tok.is(tok::l_paren) && "Expected '('!");
864 98: return TPResult::Ambiguous();
865 : }
866 :
867 : /// isCXXFunctionDeclarator - Disambiguates between a function declarator or
868 : /// a constructor-style initializer, when parsing declaration statements.
869 : /// Returns true for function declarator and false for constructor-style
870 : /// initializer.
871 : /// If during the disambiguation process a parsing error is encountered,
872 : /// the function returns true to let the declaration parsing code handle it.
873 : ///
874 : /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
875 : /// exception-specification[opt]
876 : ///
877 4190: bool Parser::isCXXFunctionDeclarator(bool warnIfAmbiguous) {
878 :
879 : // C++ 8.2p1:
880 : // The ambiguity arising from the similarity between a function-style cast and
881 : // a declaration mentioned in 6.8 can also occur in the context of a
882 : // declaration. In that context, the choice is between a function declaration
883 : // with a redundant set of parentheses around a parameter name and an object
884 : // declaration with a function-style cast as the initializer. Just as for the
885 : // ambiguities mentioned in 6.8, the resolution is to consider any construct
886 : // that could possibly be a declaration a declaration.
887 :
888 4190: TentativeParsingAction PA(*this);
889 :
890 4190: ConsumeParen();
891 4190: TPResult TPR = TryParseParameterDeclarationClause();
88: branch 2 taken
4102: branch 3 taken
0: branch 5 not taken
88: branch 6 taken
0: branch 7 not taken
4190: branch 8 taken
892 4190: if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
893 0: TPR = TPResult::False();
894 :
895 4190: SourceLocation TPLoc = Tok.getLocation();
896 4190: PA.Revert();
897 :
898 : // In case of an error, let the declaration parsing code handle it.
0: branch 2 not taken
4190: branch 3 taken
899 4190: if (TPR == TPResult::Error())
900 0: return true;
901 :
88: branch 2 taken
4102: branch 3 taken
902 4190: if (TPR == TPResult::Ambiguous()) {
903 : // Function declarator has precedence over constructor-style initializer.
904 : // Emit a warning just in case the author intended a variable definition.
10: branch 0 taken
78: branch 1 taken
905 88: if (warnIfAmbiguous)
906 : Diag(Tok, diag::warn_parens_disambiguated_as_function_decl)
907 10: << SourceRange(Tok.getLocation(), TPLoc);
908 88: return true;
909 : }
910 :
911 4102: return TPR == TPResult::True();
912 : }
913 :
914 : /// parameter-declaration-clause:
915 : /// parameter-declaration-list[opt] '...'[opt]
916 : /// parameter-declaration-list ',' '...'
917 : ///
918 : /// parameter-declaration-list:
919 : /// parameter-declaration
920 : /// parameter-declaration-list ',' parameter-declaration
921 : ///
922 : /// parameter-declaration:
923 : /// decl-specifier-seq declarator
924 : /// decl-specifier-seq declarator '=' assignment-expression
925 : /// decl-specifier-seq abstract-declarator[opt]
926 : /// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
927 : ///
928 4522: Parser::TPResult Parser::TryParseParameterDeclarationClause() {
929 :
1604: branch 1 taken
2918: branch 2 taken
930 4522: if (Tok.is(tok::r_paren))
931 1604: return TPResult::True();
932 :
933 : // parameter-declaration-list[opt] '...'[opt]
934 : // parameter-declaration-list ',' '...'
935 : //
936 : // parameter-declaration-list:
937 : // parameter-declaration
938 : // parameter-declaration-list ',' parameter-declaration
939 : //
940 5: while (1) {
941 : // '...'[opt]
61: branch 1 taken
2862: branch 2 taken
942 2923: if (Tok.is(tok::ellipsis)) {
943 61: ConsumeToken();
944 61: return TPResult::True(); // '...' is a sign of a function declarator.
945 : }
946 :
947 : // decl-specifier-seq
948 2862: TPResult TPR = TryParseDeclarationSpecifier();
2764: branch 2 taken
98: branch 3 taken
949 2862: if (TPR != TPResult::Ambiguous())
950 2764: return TPR;
951 :
952 : // declarator
953 : // abstract-declarator[opt]
954 98: TPR = TryParseDeclarator(true/*mayBeAbstract*/);
0: branch 2 not taken
98: branch 3 taken
955 98: if (TPR != TPResult::Ambiguous())
956 0: return TPR;
957 :
0: branch 1 not taken
98: branch 2 taken
958 98: if (Tok.is(tok::equal)) {
959 : // '=' assignment-expression
960 : // Parse through assignment-expression.
961 0: tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
0: branch 1 not taken
0: branch 2 not taken
962 0: if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
963 0: return TPResult::Error();
964 : }
965 :
0: branch 1 not taken
98: branch 2 taken
966 98: if (Tok.is(tok::ellipsis)) {
967 0: ConsumeToken();
968 0: return TPResult::True(); // '...' is a sign of a function declarator.
969 : }
970 :
5: branch 1 taken
93: branch 2 taken
971 98: if (Tok.isNot(tok::comma))
972 93: break;
973 5: ConsumeToken(); // the comma.
974 : }
975 :
976 93: return TPResult::Ambiguous();
977 : }
978 :
979 : /// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
980 : /// parsing as a function declarator.
981 : /// If TryParseFunctionDeclarator fully parsed the function declarator, it will
982 : /// return TPResult::Ambiguous(), otherwise it will return either False() or
983 : /// Error().
984 : ///
985 : /// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
986 : /// exception-specification[opt]
987 : ///
988 : /// exception-specification:
989 : /// 'throw' '(' type-id-list[opt] ')'
990 : ///
991 332: Parser::TPResult Parser::TryParseFunctionDeclarator() {
992 :
993 : // The '(' is already parsed.
994 :
995 332: TPResult TPR = TryParseParameterDeclarationClause();
5: branch 2 taken
327: branch 3 taken
0: branch 5 not taken
5: branch 6 taken
0: branch 7 not taken
332: branch 8 taken
996 332: if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
997 0: TPR = TPResult::False();
998 :
332: branch 2 taken
0: branch 3 not taken
0: branch 6 not taken
332: branch 7 taken
0: branch 8 not taken
332: branch 9 taken
999 332: if (TPR == TPResult::False() || TPR == TPResult::Error())
1000 0: return TPR;
1001 :
1002 : // Parse through the parens.
0: branch 1 not taken
332: branch 2 taken
1003 332: if (!SkipUntil(tok::r_paren))
1004 0: return TPResult::Error();
1005 :
1006 : // cv-qualifier-seq
336: branch 1 taken
9: branch 2 taken
332: branch 4 taken
4: branch 5 taken
0: branch 7 not taken
332: branch 8 taken
13: branch 9 taken
332: branch 10 taken
1007 677: while (Tok.is(tok::kw_const) ||
1008 : Tok.is(tok::kw_volatile) ||
1009 : Tok.is(tok::kw_restrict) )
1010 13: ConsumeToken();
1011 :
1012 : // exception-specification
22: branch 1 taken
310: branch 2 taken
1013 332: if (Tok.is(tok::kw_throw)) {
1014 22: ConsumeToken();
0: branch 1 not taken
22: branch 2 taken
1015 22: if (Tok.isNot(tok::l_paren))
1016 0: return TPResult::Error();
1017 :
1018 : // Parse through the parens after 'throw'.
1019 22: ConsumeParen();
0: branch 1 not taken
22: branch 2 taken
1020 22: if (!SkipUntil(tok::r_paren))
1021 0: return TPResult::Error();
1022 : }
1023 :
1024 332: return TPResult::Ambiguous();
1025 : }
1026 :
1027 : /// '[' constant-expression[opt] ']'
1028 : ///
1029 43: Parser::TPResult Parser::TryParseBracketDeclarator() {
1030 43: ConsumeBracket();
0: branch 1 not taken
43: branch 2 taken
1031 43: if (!SkipUntil(tok::r_square))
1032 0: return TPResult::Error();
1033 :
1034 43: return TPResult::Ambiguous();
1035 : }
Generated: 2010-02-10 01:31 by zcov