blob: 5dbc327b7134dcf877649294c3c42f886f77f1b1 [file] [log] [blame]
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +00001//===--- 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/Basic/Diagnostic.h"
17using 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 [TODO]
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/// [C++0x] static_assert-declaration: [TODO]
50/// [C++0x] static_assert '(' constant-expression ',' string-literal ')' ';'
51///
52bool Parser::isCXXDeclarationStatement() {
53 switch (Tok.getKind()) {
54 // asm-definition
55 case tok::kw_asm:
56 // namespace-alias-definition
57 case tok::kw_namespace:
58 // using-declaration
59 // using-directive
60 case tok::kw_using:
61 return true;
62 default:
63 // simple-declaration
64 return isCXXSimpleDeclaration();
65 }
66}
67
68/// isCXXSimpleDeclaration - C++-specialized function that disambiguates
69/// between a simple-declaration or an expression-statement.
70/// If during the disambiguation process a parsing error is encountered,
71/// the function returns true to let the declaration parsing code handle it.
72/// Returns false if the statement is disambiguated as expression.
73///
74/// simple-declaration:
75/// decl-specifier-seq init-declarator-list[opt] ';'
76///
77bool Parser::isCXXSimpleDeclaration() {
78 // C++ 6.8p1:
79 // There is an ambiguity in the grammar involving expression-statements and
80 // declarations: An expression-statement with a function-style explicit type
81 // conversion (5.2.3) as its leftmost subexpression can be indistinguishable
82 // from a declaration where the first declarator starts with a '('. In those
83 // cases the statement is a declaration. [Note: To disambiguate, the whole
84 // statement might have to be examined to determine if it is an
85 // expression-statement or a declaration].
86
87 // C++ 6.8p3:
88 // The disambiguation is purely syntactic; that is, the meaning of the names
89 // occurring in such a statement, beyond whether they are type-names or not,
90 // is not generally used in or changed by the disambiguation. Class
91 // templates are instantiated as necessary to determine if a qualified name
92 // is a type-name. Disambiguation precedes parsing, and a statement
93 // disambiguated as a declaration may be an ill-formed declaration.
94
95 // We don't have to parse all of the decl-specifier-seq part. There's only
96 // an ambiguity if the first decl-specifier is
97 // simple-type-specifier/typename-specifier followed by a '(', which may
98 // indicate a function-style cast expression.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +000099 // isCXXDeclarationSpecifier will return TPResult::Ambiguous() only in such
100 // a case.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000101
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000102 TPResult TPR = isCXXDeclarationSpecifier();
103 if (TPR != TPResult::Ambiguous())
104 return TPR != TPResult::False(); // Returns true for TPResult::True() or
105 // TPResult::Error().
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000106
107 // FIXME: Add statistics about the number of ambiguous statements encountered
108 // and how they were resolved (number of declarations+number of expressions).
109
110 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
111 // We need tentative parsing...
112
113 TentativeParsingAction PA(*this);
114
115 TPR = TryParseSimpleDeclaration();
116 SourceLocation TentativeParseLoc = Tok.getLocation();
117
118 PA.Revert();
119
120 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000121 if (TPR == TPResult::Error())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000122 return true;
123
124 // Declarations take precedence over expressions.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000125 if (TPR == TPResult::Ambiguous())
126 TPR = TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000127
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000128 assert(TPR == TPResult::True() || TPR == TPResult::False());
129 if (TPR == TPResult::True() && Tok.isNot(tok::kw_void)) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000130 // We have a declaration that looks like a functional cast; there's a high
131 // chance that the author intended the statement to be an expression.
132 // Emit a warning.
133 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
134 "declaration", SourceRange(Tok.getLocation(), TentativeParseLoc));
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000135 } else if (TPR == TPResult::False() && Tok.is(tok::kw_void)) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000136 // A functional cast to 'void' expression ? Warning..
137 Diag(Tok.getLocation(), diag::warn_statement_disambiguation,
138 "expression", SourceRange(Tok.getLocation(), TentativeParseLoc));
139 }
140
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000141 return TPR == TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000142}
143
144/// simple-declaration:
145/// decl-specifier-seq init-declarator-list[opt] ';'
146///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000147Parser::TPResult Parser::TryParseSimpleDeclaration() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000148 // We know that we have a simple-type-specifier/typename-specifier followed
149 // by a '('.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000150 assert(isCXXDeclarationSpecifier() == TPResult::Ambiguous());
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000151
152 if (Tok.is(tok::kw_typeof))
153 TryParseTypeofSpecifier();
154 else
155 ConsumeToken();
156
157 assert(Tok.is(tok::l_paren) && "Expected '('");
158
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000159 TPResult TPR = TryParseInitDeclaratorList();
160 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000161 return TPR;
162
163 if (Tok.isNot(tok::semi))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000164 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000165
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000166 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000167}
168
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000169/// init-declarator-list:
170/// init-declarator
171/// init-declarator-list ',' init-declarator
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000172///
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000173/// init-declarator:
174/// declarator initializer[opt]
175/// [GNU] declarator simple-asm-expr[opt] attributes[opt] initializer[opt]
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000176///
177/// initializer:
178/// '=' initializer-clause
179/// '(' expression-list ')'
180///
181/// initializer-clause:
182/// assignment-expression
183/// '{' initializer-list ','[opt] '}'
184/// '{' '}'
185///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000186Parser::TPResult Parser::TryParseInitDeclaratorList() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000187 // GCC only examines the first declarator for disambiguation:
188 // i.e:
189 // int(x), ++x; // GCC regards it as ill-formed declaration.
190 //
191 // Comeau and MSVC will regard the above statement as correct expression.
192 // Clang examines all of the declarators and also regards the above statement
193 // as correct expression.
194
195 while (1) {
196 // declarator
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000197 TPResult TPR = TryParseDeclarator(false/*mayBeAbstract*/);
198 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000199 return TPR;
200
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000201 // [GNU] simple-asm-expr[opt] attributes[opt]
202 if (Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000203 return TPResult::True();
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000204
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000205 // initializer[opt]
206 if (Tok.is(tok::l_paren)) {
207 // Parse through the parens.
208 ConsumeParen();
209 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000210 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000211 } else if (Tok.is(tok::equal)) {
212 // MSVC won't examine the rest of declarators if '=' is encountered, it
213 // will conclude that it is a declaration.
214 // Comeau and Clang will examine the rest of declarators.
215 // Note that "int(x) = {0}, ++x;" will be interpreted as ill-formed
216 // expression.
217 //
218 // Parse through the initializer-clause.
219 SkipUntil(tok::comma, true/*StopAtSemi*/, true/*DontConsume*/);
220 }
221
222 if (Tok.isNot(tok::comma))
223 break;
224 ConsumeToken(); // the comma.
225 }
226
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000227 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000228}
229
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000230/// isCXXConditionDeclaration - Disambiguates between a declaration or an
231/// expression for a condition of a if/switch/while/for statement.
232/// If during the disambiguation process a parsing error is encountered,
233/// the function returns true to let the declaration parsing code handle it.
234///
235/// condition:
236/// expression
237/// type-specifier-seq declarator '=' assignment-expression
238/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
239/// '=' assignment-expression
240///
241bool Parser::isCXXConditionDeclaration() {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000242 TPResult TPR = isCXXDeclarationSpecifier();
243 if (TPR != TPResult::Ambiguous())
244 return TPR != TPResult::False(); // Returns true for TPResult::True() or
245 // TPResult::Error().
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000246
247 // FIXME: Add statistics about the number of ambiguous statements encountered
248 // and how they were resolved (number of declarations+number of expressions).
249
250 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
251 // We need tentative parsing...
252
253 TentativeParsingAction PA(*this);
254
255 // type-specifier-seq
256 if (Tok.is(tok::kw_typeof))
257 TryParseTypeofSpecifier();
258 else
259 ConsumeToken();
260 assert(Tok.is(tok::l_paren) && "Expected '('");
261
262 // declarator
263 TPR = TryParseDeclarator(false/*mayBeAbstract*/);
264
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000265 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000266 if (TPR == TPResult::Error())
267 TPR = TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000268
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000269 if (TPR == TPResult::Ambiguous()) {
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000270 // '='
271 // [GNU] simple-asm-expr[opt] attributes[opt]
272 if (Tok.is(tok::equal) ||
273 Tok.is(tok::kw_asm) || Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000274 TPR = TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000275 else
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000276 TPR = TPResult::False();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000277 }
278
Argyrios Kyrtzidisca35baa2008-10-05 15:19:49 +0000279 PA.Revert();
280
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000281 assert(TPR == TPResult::True() || TPR == TPResult::False());
282 return TPR == TPResult::True();
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000283}
284
Argyrios Kyrtzidisd3dbbb62008-10-05 21:10:08 +0000285/// isCXXTypeIdInParens - Assumes that a '(' was parsed and now we want to
286/// know whether the parens contain an expression or a type-id.
287/// Returns true for a type-id and false for an expression.
288/// If during the disambiguation process a parsing error is encountered,
289/// the function returns true to let the declaration parsing code handle it.
290///
291/// type-id:
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000292/// type-specifier-seq abstract-declarator[opt]
293///
294bool Parser::isCXXTypeIdInParens() {
Argyrios Kyrtzidisd3dbbb62008-10-05 21:10:08 +0000295
296 // C++ 8.2p2:
297 // The ambiguity arising from the similarity between a function-style cast and
298 // a type-id can occur in different contexts. The ambiguity appears as a
299 // choice between a function-style cast expression and a declaration of a
300 // type. The resolution is that any construct that could possibly be a type-id
301 // in its syntactic context shall be considered a type-id.
302
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000303 TPResult TPR = isCXXDeclarationSpecifier();
304 if (TPR != TPResult::Ambiguous())
305 return TPR != TPResult::False(); // Returns true for TPResult::True() or
306 // TPResult::Error().
307
308 // FIXME: Add statistics about the number of ambiguous statements encountered
309 // and how they were resolved (number of declarations+number of expressions).
310
311 // Ok, we have a simple-type-specifier/typename-specifier followed by a '('.
312 // We need tentative parsing...
313
314 TentativeParsingAction PA(*this);
315
316 // type-specifier-seq
317 if (Tok.is(tok::kw_typeof))
318 TryParseTypeofSpecifier();
319 else
320 ConsumeToken();
321 assert(Tok.is(tok::l_paren) && "Expected '('");
322
323 // declarator
324 TPR = TryParseDeclarator(true/*mayBeAbstract*/, false/*mayHaveIdentifier*/);
325
326 // In case of an error, let the declaration parsing code handle it.
327 if (TPR == TPResult::Error())
328 TPR = TPResult::True();
329
330 if (TPR == TPResult::Ambiguous()) {
331 // We are supposed to be inside parens, so if after the abstract declarator
332 // we encounter a ')' this is a type-id, otherwise it's an expression.
333 if (Tok.is(tok::r_paren))
334 TPR = TPResult::True();
335 else
336 TPR = TPResult::False();
337 }
338
339 PA.Revert();
340
341 assert(TPR == TPResult::True() || TPR == TPResult::False());
342 return TPR == TPResult::True();
343}
344
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000345/// declarator:
346/// direct-declarator
347/// ptr-operator declarator
348///
349/// direct-declarator:
350/// declarator-id
351/// direct-declarator '(' parameter-declaration-clause ')'
352/// cv-qualifier-seq[opt] exception-specification[opt]
353/// direct-declarator '[' constant-expression[opt] ']'
354/// '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000355/// [GNU] '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000356///
357/// abstract-declarator:
358/// ptr-operator abstract-declarator[opt]
359/// direct-abstract-declarator
360///
361/// direct-abstract-declarator:
362/// direct-abstract-declarator[opt]
363/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
364/// exception-specification[opt]
365/// direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
366/// '(' abstract-declarator ')'
367///
368/// ptr-operator:
369/// '*' cv-qualifier-seq[opt]
370/// '&'
371/// [C++0x] '&&' [TODO]
372/// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO]
373///
374/// cv-qualifier-seq:
375/// cv-qualifier cv-qualifier-seq[opt]
376///
377/// cv-qualifier:
378/// 'const'
379/// 'volatile'
380///
381/// declarator-id:
382/// id-expression
383///
384/// id-expression:
385/// unqualified-id
386/// qualified-id [TODO]
387///
388/// unqualified-id:
389/// identifier
390/// operator-function-id [TODO]
391/// conversion-function-id [TODO]
392/// '~' class-name [TODO]
393/// template-id [TODO]
394///
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000395Parser::TPResult Parser::TryParseDeclarator(bool mayBeAbstract,
396 bool mayHaveIdentifier) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000397 // declarator:
398 // direct-declarator
399 // ptr-operator declarator
400
401 while (1) {
402 if (Tok.is(tok::star) || Tok.is(tok::amp)) {
403 // ptr-operator
404 ConsumeToken();
405 while (Tok.is(tok::kw_const) ||
406 Tok.is(tok::kw_volatile) ||
407 Tok.is(tok::kw_restrict) )
408 ConsumeToken();
409 } else {
410 break;
411 }
412 }
413
414 // direct-declarator:
415 // direct-abstract-declarator:
416
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000417 if (Tok.is(tok::identifier) && mayHaveIdentifier) {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000418 // declarator-id
419 ConsumeToken();
420 } else if (Tok.is(tok::l_paren)) {
Argyrios Kyrtzidisd3616a82008-10-05 23:15:41 +0000421 ConsumeParen();
422 if (mayBeAbstract &&
423 (Tok.is(tok::r_paren) || // 'int()' is a function.
424 Tok.is(tok::ellipsis) || // 'int(...)' is a function.
425 isDeclarationSpecifier())) { // 'int(int)' is a function.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000426 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
427 // exception-specification[opt]
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000428 TPResult TPR = TryParseFunctionDeclarator();
429 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000430 return TPR;
431 } else {
432 // '(' declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000433 // '(' attributes declarator ')'
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000434 // '(' abstract-declarator ')'
Argyrios Kyrtzidis1ee2c432008-10-05 14:27:18 +0000435 if (Tok.is(tok::kw___attribute))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000436 return TPResult::True(); // attributes indicate declaration
Argyrios Kyrtzidis78c8d802008-10-05 19:56:22 +0000437 TPResult TPR = TryParseDeclarator(mayBeAbstract, mayHaveIdentifier);
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000438 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000439 return TPR;
440 if (Tok.isNot(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000441 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000442 ConsumeParen();
443 }
444 } else if (!mayBeAbstract) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000445 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000446 }
447
448 while (1) {
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000449 TPResult TPR(TPResult::Ambiguous());
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000450
451 if (Tok.is(tok::l_paren)) {
Argyrios Kyrtzidisd3616a82008-10-05 23:15:41 +0000452 // Check whether we have a function declarator or a possible ctor-style
453 // initializer that follows the declarator. Note that ctor-style
454 // initializers are not possible in contexts where abstract declarators
455 // are allowed.
456 if (!mayBeAbstract && !isCXXFunctionDeclarator())
457 break;
458
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000459 // direct-declarator '(' parameter-declaration-clause ')'
460 // cv-qualifier-seq[opt] exception-specification[opt]
Argyrios Kyrtzidisd3616a82008-10-05 23:15:41 +0000461 ConsumeParen();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000462 TPR = TryParseFunctionDeclarator();
463 } else if (Tok.is(tok::l_square)) {
464 // direct-declarator '[' constant-expression[opt] ']'
465 // direct-abstract-declarator[opt] '[' constant-expression[opt] ']'
466 TPR = TryParseBracketDeclarator();
467 } else {
468 break;
469 }
470
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000471 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000472 return TPR;
473 }
474
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000475 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000476}
477
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000478/// isCXXDeclarationSpecifier - Returns TPResult::True() if it is a declaration
479/// specifier, TPResult::False() if it is not, TPResult::Ambiguous() if it could
480/// be either a decl-specifier or a function-style cast, and TPResult::Error()
481/// if a parsing error was found and reported.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000482///
483/// decl-specifier:
484/// storage-class-specifier
485/// type-specifier
486/// function-specifier
487/// 'friend'
488/// 'typedef'
489/// [GNU] attributes declaration-specifiers[opt]
490///
491/// storage-class-specifier:
492/// 'register'
493/// 'static'
494/// 'extern'
495/// 'mutable'
496/// 'auto'
497/// [GNU] '__thread'
498///
499/// function-specifier:
500/// 'inline'
501/// 'virtual'
502/// 'explicit'
503///
504/// typedef-name:
505/// identifier
506///
507/// type-specifier:
508/// simple-type-specifier
509/// class-specifier
510/// enum-specifier
511/// elaborated-type-specifier
512/// typename-specifier [TODO]
513/// cv-qualifier
514///
515/// simple-type-specifier:
516/// '::'[opt] nested-name-specifier[opt] type-name [TODO]
517/// '::'[opt] nested-name-specifier 'template'
518/// simple-template-id [TODO]
519/// 'char'
520/// 'wchar_t'
521/// 'bool'
522/// 'short'
523/// 'int'
524/// 'long'
525/// 'signed'
526/// 'unsigned'
527/// 'float'
528/// 'double'
529/// 'void'
530/// [GNU] typeof-specifier
531/// [GNU] '_Complex'
532/// [C++0x] 'auto' [TODO]
533///
534/// type-name:
535/// class-name
536/// enum-name
537/// typedef-name
538///
539/// elaborated-type-specifier:
540/// class-key '::'[opt] nested-name-specifier[opt] identifier
541/// class-key '::'[opt] nested-name-specifier[opt] 'template'[opt]
542/// simple-template-id
543/// 'enum' '::'[opt] nested-name-specifier[opt] identifier
544///
545/// enum-name:
546/// identifier
547///
548/// enum-specifier:
549/// 'enum' identifier[opt] '{' enumerator-list[opt] '}'
550/// 'enum' identifier[opt] '{' enumerator-list ',' '}'
551///
552/// class-specifier:
553/// class-head '{' member-specification[opt] '}'
554///
555/// class-head:
556/// class-key identifier[opt] base-clause[opt]
557/// class-key nested-name-specifier identifier base-clause[opt]
558/// class-key nested-name-specifier[opt] simple-template-id
559/// base-clause[opt]
560///
561/// class-key:
562/// 'class'
563/// 'struct'
564/// 'union'
565///
566/// cv-qualifier:
567/// 'const'
568/// 'volatile'
569/// [GNU] restrict
570///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000571Parser::TPResult Parser::isCXXDeclarationSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000572 switch (Tok.getKind()) {
573 // decl-specifier:
574 // storage-class-specifier
575 // type-specifier
576 // function-specifier
577 // 'friend'
578 // 'typedef'
579
580 case tok::kw_friend:
581 case tok::kw_typedef:
582 // storage-class-specifier
583 case tok::kw_register:
584 case tok::kw_static:
585 case tok::kw_extern:
586 case tok::kw_mutable:
587 case tok::kw_auto:
588 case tok::kw___thread:
589 // function-specifier
590 case tok::kw_inline:
591 case tok::kw_virtual:
592 case tok::kw_explicit:
593
594 // type-specifier:
595 // simple-type-specifier
596 // class-specifier
597 // enum-specifier
598 // elaborated-type-specifier
599 // typename-specifier
600 // cv-qualifier
601
602 // class-specifier
603 // elaborated-type-specifier
604 case tok::kw_class:
605 case tok::kw_struct:
606 case tok::kw_union:
607 // enum-specifier
608 case tok::kw_enum:
609 // cv-qualifier
610 case tok::kw_const:
611 case tok::kw_volatile:
612
613 // GNU
614 case tok::kw_restrict:
615 case tok::kw__Complex:
616 case tok::kw___attribute:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000617 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000618
619 // The ambiguity resides in a simple-type-specifier/typename-specifier
620 // followed by a '('. The '(' could either be the start of:
621 //
622 // direct-declarator:
623 // '(' declarator ')'
624 //
625 // direct-abstract-declarator:
626 // '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
627 // exception-specification[opt]
628 // '(' abstract-declarator ')'
629 //
630 // or part of a function-style cast expression:
631 //
632 // simple-type-specifier '(' expression-list[opt] ')'
633 //
634
635 // simple-type-specifier:
636
637 case tok::identifier:
638 if (!Actions.isTypeName(*Tok.getIdentifierInfo(), CurScope))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000639 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000640 // FALL THROUGH.
641
642 case tok::kw_char:
643 case tok::kw_wchar_t:
644 case tok::kw_bool:
645 case tok::kw_short:
646 case tok::kw_int:
647 case tok::kw_long:
648 case tok::kw_signed:
649 case tok::kw_unsigned:
650 case tok::kw_float:
651 case tok::kw_double:
652 case tok::kw_void:
653 if (NextToken().is(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000654 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000655
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000656 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000657
658 // GNU typeof support.
659 case tok::kw_typeof: {
660 if (NextToken().isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000661 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000662
663 TentativeParsingAction PA(*this);
664
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000665 TPResult TPR = TryParseTypeofSpecifier();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000666 bool isFollowedByParen = Tok.is(tok::l_paren);
667
668 PA.Revert();
669
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000670 if (TPR == TPResult::Error())
671 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000672
673 if (isFollowedByParen)
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000674 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000675
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000676 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000677 }
678
679 default:
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000680 return TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000681 }
682}
683
684/// [GNU] typeof-specifier:
685/// 'typeof' '(' expressions ')'
686/// 'typeof' '(' type-name ')'
687///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000688Parser::TPResult Parser::TryParseTypeofSpecifier() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000689 assert(Tok.is(tok::kw_typeof) && "Expected 'typeof'!");
690 ConsumeToken();
691
692 assert(Tok.is(tok::l_paren) && "Expected '('");
693 // Parse through the parens after 'typeof'.
694 ConsumeParen();
695 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000696 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000697
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000698 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000699}
700
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000701Parser::TPResult Parser::TryParseDeclarationSpecifier() {
702 TPResult TPR = isCXXDeclarationSpecifier();
703 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000704 return TPR;
705
706 if (Tok.is(tok::kw_typeof))
707 TryParseTypeofSpecifier();
708 else
709 ConsumeToken();
710
711 assert(Tok.is(tok::l_paren) && "Expected '('!");
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000712 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000713}
714
715/// isCXXFunctionDeclarator - Disambiguates between a function declarator or
716/// a constructor-style initializer, when parsing declaration statements.
717/// Returns true for function declarator and false for constructor-style
718/// initializer.
719/// If during the disambiguation process a parsing error is encountered,
720/// the function returns true to let the declaration parsing code handle it.
721///
722/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
723/// exception-specification[opt]
724///
725bool Parser::isCXXFunctionDeclarator() {
Argyrios Kyrtzidisd3dbbb62008-10-05 21:10:08 +0000726
727 // C++ 8.2p1:
728 // The ambiguity arising from the similarity between a function-style cast and
729 // a declaration mentioned in 6.8 can also occur in the context of a
730 // declaration. In that context, the choice is between a function declaration
731 // with a redundant set of parentheses around a parameter name and an object
732 // declaration with a function-style cast as the initializer. Just as for the
733 // ambiguities mentioned in 6.8, the resolution is to consider any construct
734 // that could possibly be a declaration a declaration.
735
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000736 TentativeParsingAction PA(*this);
737
738 ConsumeParen();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000739 TPResult TPR = TryParseParameterDeclarationClause();
740 if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
741 TPR = TPResult::False();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000742
743 PA.Revert();
744
745 // In case of an error, let the declaration parsing code handle it.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000746 if (TPR == TPResult::Error())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000747 return true;
748
749 // Function declarator has precedence over constructor-style initializer.
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000750 if (TPR == TPResult::Ambiguous())
751 return true;
752
753 return TPR == TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000754}
755
756/// parameter-declaration-clause:
757/// parameter-declaration-list[opt] '...'[opt]
758/// parameter-declaration-list ',' '...'
759///
760/// parameter-declaration-list:
761/// parameter-declaration
762/// parameter-declaration-list ',' parameter-declaration
763///
764/// parameter-declaration:
765/// decl-specifier-seq declarator
766/// decl-specifier-seq declarator '=' assignment-expression
767/// decl-specifier-seq abstract-declarator[opt]
768/// decl-specifier-seq abstract-declarator[opt] '=' assignment-expression
769///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000770Parser::TPResult Parser::TryParseParameterDeclarationClause() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000771
772 if (Tok.is(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000773 return TPResult::True();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000774
775 // parameter-declaration-list[opt] '...'[opt]
776 // parameter-declaration-list ',' '...'
777 //
778 // parameter-declaration-list:
779 // parameter-declaration
780 // parameter-declaration-list ',' parameter-declaration
781 //
782 while (1) {
783 // '...'[opt]
784 if (Tok.is(tok::ellipsis)) {
785 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000786 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000787 }
788
789 // decl-specifier-seq
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000790 TPResult TPR = TryParseDeclarationSpecifier();
791 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000792 return TPR;
793
794 // declarator
795 // abstract-declarator[opt]
796 TPR = TryParseDeclarator(true/*mayBeAbstract*/);
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000797 if (TPR != TPResult::Ambiguous())
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000798 return TPR;
799
800 if (Tok.is(tok::equal)) {
801 // '=' assignment-expression
802 // Parse through assignment-expression.
803 tok::TokenKind StopToks[3] ={ tok::comma, tok::ellipsis, tok::r_paren };
804 if (!SkipUntil(StopToks, 3, true/*StopAtSemi*/, true/*DontConsume*/))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000805 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000806 }
807
808 if (Tok.is(tok::ellipsis)) {
809 ConsumeToken();
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000810 return TPResult::True(); // '...' is a sign of a function declarator.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000811 }
812
813 if (Tok.isNot(tok::comma))
814 break;
815 ConsumeToken(); // the comma.
816 }
817
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000818 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000819}
820
Argyrios Kyrtzidisd3616a82008-10-05 23:15:41 +0000821/// TryParseFunctionDeclarator - We parsed a '(' and we want to try to continue
822/// parsing as a function declarator.
823/// If TryParseFunctionDeclarator fully parsed the function declarator, it will
824/// return TPResult::Ambiguous(), otherwise it will return either False() or
825/// Error().
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000826///
827/// '(' parameter-declaration-clause ')' cv-qualifier-seq[opt]
828/// exception-specification[opt]
829///
830/// exception-specification:
831/// 'throw' '(' type-id-list[opt] ')'
832///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000833Parser::TPResult Parser::TryParseFunctionDeclarator() {
Argyrios Kyrtzidisd3616a82008-10-05 23:15:41 +0000834
835 // The '(' is already parsed.
836
837 TPResult TPR = TryParseParameterDeclarationClause();
838 if (TPR == TPResult::Ambiguous() && Tok.isNot(tok::r_paren))
839 TPR = TPResult::False();
840
841 if (TPR == TPResult::False() || TPR == TPResult::Error())
842 return TPR;
843
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000844 // Parse through the parens.
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000845 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000846 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000847
848 // cv-qualifier-seq
849 while (Tok.is(tok::kw_const) ||
850 Tok.is(tok::kw_volatile) ||
851 Tok.is(tok::kw_restrict) )
852 ConsumeToken();
853
854 // exception-specification
855 if (Tok.is(tok::kw_throw)) {
856 ConsumeToken();
857 if (Tok.isNot(tok::l_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000858 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000859
860 // Parse through the parens after 'throw'.
861 ConsumeParen();
862 if (!SkipUntil(tok::r_paren))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000863 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000864 }
865
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000866 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000867}
868
869/// '[' constant-expression[opt] ']'
870///
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000871Parser::TPResult Parser::TryParseBracketDeclarator() {
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000872 ConsumeBracket();
873 if (!SkipUntil(tok::r_square))
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000874 return TPResult::Error();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000875
Argyrios Kyrtzidisb9f34192008-10-05 18:52:21 +0000876 return TPResult::Ambiguous();
Argyrios Kyrtzidis5404a152008-10-05 00:06:24 +0000877}