blob: 2fe3bcf2db609ec169d769f20d8a08fe60e2dfe4 [file] [log] [blame]
Reid Spencer5f016e22007-07-11 17:01:13 +00001//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner0bc735f2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Reid Spencer5f016e22007-07-11 17:01:13 +00007//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the Expression parsing implementation for C++.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Basic/Diagnostic.h"
15#include "clang/Parse/Parser.h"
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +000016#include "clang/Parse/DeclSpec.h"
Reid Spencer5f016e22007-07-11 17:01:13 +000017using namespace clang;
18
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +000019/// ParseCXXScopeSpecifier - Parse global scope or nested-name-specifier.
20///
21/// '::'[opt] nested-name-specifier
22/// '::'
23///
24/// nested-name-specifier:
25/// type-name '::'
26/// namespace-name '::'
27/// nested-name-specifier identifier '::'
28/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
29///
30void Parser::ParseCXXScopeSpecifier(CXXScopeSpec &SS) {
31 assert(isTokenCXXScopeSpecifier() && "Not scope specifier!");
32
33 if (Tok.is(tok::annot_cxxscope)) {
34 SS.setScopeRep(Tok.getAnnotationValue());
35 SS.setRange(Tok.getAnnotationRange());
36 ConsumeToken();
37 return;
38 }
39
40 SS.setBeginLoc(Tok.getLocation());
41
42 // '::'
43
44 if (Tok.is(tok::coloncolon)) {
45 // Global scope.
46 SourceLocation CCLoc = ConsumeToken();
47 SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
48 SS.setEndLoc(CCLoc);
49 }
50
51 // nested-name-specifier:
52 // type-name '::'
53 // namespace-name '::'
54 // nested-name-specifier identifier '::'
55 // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
56
57 while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
58 IdentifierInfo *II = Tok.getIdentifierInfo();
59 SourceLocation IdLoc = ConsumeToken();
60 assert(Tok.is(tok::coloncolon) &&
61 "NextToken() not working properly!");
62 SourceLocation CCLoc = ConsumeToken();
63 if (SS.isInvalid())
64 continue;
65
66 SS.setScopeRep(
67 Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II) );
68 SS.setEndLoc(CCLoc);
69 }
70}
71
72/// ParseCXXIdExpression - Handle id-expression.
73///
74/// id-expression:
75/// unqualified-id
76/// qualified-id
77///
78/// unqualified-id:
79/// identifier
80/// operator-function-id
81/// conversion-function-id [TODO]
82/// '~' class-name [TODO]
83/// template-id [TODO]
84///
85/// qualified-id:
86/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
87/// '::' identifier
88/// '::' operator-function-id
89/// '::' template-id [TODO]
90///
91/// nested-name-specifier:
92/// type-name '::'
93/// namespace-name '::'
94/// nested-name-specifier identifier '::'
95/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
96///
97/// NOTE: The standard specifies that, for qualified-id, the parser does not
98/// expect:
99///
100/// '::' conversion-function-id
101/// '::' '~' class-name
102///
103/// This may cause a slight inconsistency on diagnostics:
104///
105/// class C {};
106/// namespace A {}
107/// void f() {
108/// :: A :: ~ C(); // Some Sema error about using destructor with a
109/// // namespace.
110/// :: ~ C(); // Some Parser error like 'unexpected ~'.
111/// }
112///
113/// We simplify the parser a bit and make it work like:
114///
115/// qualified-id:
116/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
117/// '::' unqualified-id
118///
119/// That way Sema can handle and report similar errors for namespaces and the
120/// global scope.
121///
122Parser::ExprResult Parser::ParseCXXIdExpression() {
123 // qualified-id:
124 // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
125 // '::' unqualified-id
126 //
127 CXXScopeSpec SS;
128 if (isTokenCXXScopeSpecifier())
129 ParseCXXScopeSpecifier(SS);
130
131 // unqualified-id:
132 // identifier
133 // operator-function-id
134 // conversion-function-id [TODO]
135 // '~' class-name [TODO]
136 // template-id [TODO]
137 //
138 switch (Tok.getKind()) {
139 default:
140 return Diag(Tok, diag::err_expected_unqualified_id);
141
142 case tok::identifier: {
143 // Consume the identifier so that we can see if it is followed by a '('.
144 IdentifierInfo &II = *Tok.getIdentifierInfo();
145 SourceLocation L = ConsumeToken();
146 return Actions.ActOnIdentifierExpr(CurScope, L, II,
147 Tok.is(tok::l_paren), &SS);
148 }
149
150 case tok::kw_operator: {
151 SourceLocation OperatorLoc = Tok.getLocation();
152 if (IdentifierInfo *II = MaybeParseOperatorFunctionId()) {
153 return Actions.ActOnIdentifierExpr(CurScope, OperatorLoc, *II,
154 Tok.is(tok::l_paren), &SS);
155 }
156 // FIXME: Handle conversion-function-id.
157 unsigned DiagID = PP.getDiagnostics().getCustomDiagID(Diagnostic::Error,
158 "expected operator-function-id");
159 return Diag(Tok, DiagID);
160 }
161
162 } // switch.
163
164 assert(0 && "The switch was supposed to take care everything.");
165}
166
Reid Spencer5f016e22007-07-11 17:01:13 +0000167/// ParseCXXCasts - This handles the various ways to cast expressions to another
168/// type.
169///
170/// postfix-expression: [C++ 5.2p1]
171/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
172/// 'static_cast' '<' type-name '>' '(' expression ')'
173/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
174/// 'const_cast' '<' type-name '>' '(' expression ')'
175///
176Parser::ExprResult Parser::ParseCXXCasts() {
177 tok::TokenKind Kind = Tok.getKind();
178 const char *CastName = 0; // For error messages
179
180 switch (Kind) {
181 default: assert(0 && "Unknown C++ cast!"); abort();
182 case tok::kw_const_cast: CastName = "const_cast"; break;
183 case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
184 case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
185 case tok::kw_static_cast: CastName = "static_cast"; break;
186 }
187
188 SourceLocation OpLoc = ConsumeToken();
189 SourceLocation LAngleBracketLoc = Tok.getLocation();
190
191 if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
192 return ExprResult(true);
193
194 TypeTy *CastTy = ParseTypeName();
195 SourceLocation RAngleBracketLoc = Tok.getLocation();
196
197 if (ExpectAndConsume(tok::greater, diag::err_expected_greater)) {
198 Diag(LAngleBracketLoc, diag::err_matching, "<");
199 return ExprResult(true);
200 }
201
202 SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
203
Chris Lattner4e1d99a2007-10-09 17:41:39 +0000204 if (Tok.isNot(tok::l_paren)) {
Reid Spencer5f016e22007-07-11 17:01:13 +0000205 Diag(Tok, diag::err_expected_lparen_after, CastName);
206 return ExprResult(true);
207 }
208
209 ExprResult Result = ParseSimpleParenExpression(RParenLoc);
210
211 if (!Result.isInvalid)
Douglas Gregor49badde2008-10-27 19:41:14 +0000212 Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
213 LAngleBracketLoc, CastTy, RAngleBracketLoc,
214 LParenLoc, Result.Val, RParenLoc);
Reid Spencer5f016e22007-07-11 17:01:13 +0000215
216 return Result;
217}
218
219/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
220///
221/// boolean-literal: [C++ 2.13.5]
222/// 'true'
223/// 'false'
224Parser::ExprResult Parser::ParseCXXBoolLiteral() {
225 tok::TokenKind Kind = Tok.getKind();
Steve Naroff1b273c42007-09-16 14:56:35 +0000226 return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
Reid Spencer5f016e22007-07-11 17:01:13 +0000227}
Chris Lattner50dd2892008-02-26 00:51:44 +0000228
229/// ParseThrowExpression - This handles the C++ throw expression.
230///
231/// throw-expression: [C++ 15]
232/// 'throw' assignment-expression[opt]
233Parser::ExprResult Parser::ParseThrowExpression() {
234 assert(Tok.is(tok::kw_throw) && "Not throw!");
Chris Lattner50dd2892008-02-26 00:51:44 +0000235 SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token.
Chris Lattner3e3d3102008-04-06 06:03:03 +0000236
Chris Lattner2a2819a2008-04-06 06:02:23 +0000237 // If the current token isn't the start of an assignment-expression,
238 // then the expression is not present. This handles things like:
239 // "C ? throw : (void)42", which is crazy but legal.
240 switch (Tok.getKind()) { // FIXME: move this predicate somewhere common.
241 case tok::semi:
242 case tok::r_paren:
243 case tok::r_square:
244 case tok::r_brace:
245 case tok::colon:
246 case tok::comma:
Chris Lattner50dd2892008-02-26 00:51:44 +0000247 return Actions.ActOnCXXThrow(ThrowLoc);
248
Chris Lattner2a2819a2008-04-06 06:02:23 +0000249 default:
Chris Lattner3e3d3102008-04-06 06:03:03 +0000250 ExprResult Expr = ParseAssignmentExpression();
Chris Lattner2a2819a2008-04-06 06:02:23 +0000251 if (Expr.isInvalid) return Expr;
252 return Actions.ActOnCXXThrow(ThrowLoc, Expr.Val);
253 }
Chris Lattner50dd2892008-02-26 00:51:44 +0000254}
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +0000255
256/// ParseCXXThis - This handles the C++ 'this' pointer.
257///
258/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
259/// a non-lvalue expression whose value is the address of the object for which
260/// the function is called.
261Parser::ExprResult Parser::ParseCXXThis() {
262 assert(Tok.is(tok::kw_this) && "Not 'this'!");
263 SourceLocation ThisLoc = ConsumeToken();
Argyrios Kyrtzidis289d7732008-08-16 19:34:46 +0000264 return Actions.ActOnCXXThis(ThisLoc);
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +0000265}
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000266
267/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
268/// Can be interpreted either as function-style casting ("int(x)")
269/// or class type construction ("ClassType(x,y,z)")
270/// or creation of a value-initialized type ("int()").
271///
272/// postfix-expression: [C++ 5.2p1]
273/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
274/// typename-specifier '(' expression-list[opt] ')' [TODO]
275///
276Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
277 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
278 TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
279
280 assert(Tok.is(tok::l_paren) && "Expected '('!");
281 SourceLocation LParenLoc = ConsumeParen();
282
283 ExprListTy Exprs;
284 CommaLocsTy CommaLocs;
285
286 if (Tok.isNot(tok::r_paren)) {
287 if (ParseExpressionList(Exprs, CommaLocs)) {
288 SkipUntil(tok::r_paren);
289 return ExprResult(true);
290 }
291 }
292
293 // Match the ')'.
294 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
295
296 assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
297 "Unexpected number of commas!");
298 return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
299 LParenLoc,
300 &Exprs[0], Exprs.size(),
301 &CommaLocs[0], RParenLoc);
302}
303
Argyrios Kyrtzidis71b914b2008-09-09 20:38:47 +0000304/// ParseCXXCondition - if/switch/while/for condition expression.
305///
306/// condition:
307/// expression
308/// type-specifier-seq declarator '=' assignment-expression
309/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
310/// '=' assignment-expression
311///
312Parser::ExprResult Parser::ParseCXXCondition() {
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000313 if (!isCXXConditionDeclaration())
Argyrios Kyrtzidis71b914b2008-09-09 20:38:47 +0000314 return ParseExpression(); // expression
315
316 SourceLocation StartLoc = Tok.getLocation();
317
318 // type-specifier-seq
319 DeclSpec DS;
320 ParseSpecifierQualifierList(DS);
321
322 // declarator
323 Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
324 ParseDeclarator(DeclaratorInfo);
325
326 // simple-asm-expr[opt]
327 if (Tok.is(tok::kw_asm)) {
328 ExprResult AsmLabel = ParseSimpleAsm();
329 if (AsmLabel.isInvalid) {
330 SkipUntil(tok::semi);
331 return true;
332 }
333 DeclaratorInfo.setAsmLabel(AsmLabel.Val);
334 }
335
336 // If attributes are present, parse them.
337 if (Tok.is(tok::kw___attribute))
338 DeclaratorInfo.AddAttributes(ParseAttributes());
339
340 // '=' assignment-expression
341 if (Tok.isNot(tok::equal))
342 return Diag(Tok, diag::err_expected_equal_after_declarator);
343 SourceLocation EqualLoc = ConsumeToken();
344 ExprResult AssignExpr = ParseAssignmentExpression();
345 if (AssignExpr.isInvalid)
346 return true;
347
348 return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
349 DeclaratorInfo,
350 EqualLoc, AssignExpr.Val);
351}
352
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000353/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
354/// This should only be called when the current token is known to be part of
355/// simple-type-specifier.
356///
357/// simple-type-specifier:
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000358/// '::'[opt] nested-name-specifier[opt] type-name
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000359/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
360/// char
361/// wchar_t
362/// bool
363/// short
364/// int
365/// long
366/// signed
367/// unsigned
368/// float
369/// double
370/// void
371/// [GNU] typeof-specifier
372/// [C++0x] auto [TODO]
373///
374/// type-name:
375/// class-name
376/// enum-name
377/// typedef-name
378///
379void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000380 // Annotate typenames and C++ scope specifiers.
381 TryAnnotateTypeOrScopeToken();
382
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000383 DS.SetRangeStart(Tok.getLocation());
384 const char *PrevSpec;
385 SourceLocation Loc = Tok.getLocation();
386
387 switch (Tok.getKind()) {
388 default:
389 assert(0 && "Not a simple-type-specifier token!");
390 abort();
391
392 // type-name
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000393 case tok::annot_qualtypename: {
394 DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
395 Tok.getAnnotationValue());
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000396 break;
397 }
398
399 // builtin types
400 case tok::kw_short:
401 DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
402 break;
403 case tok::kw_long:
404 DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
405 break;
406 case tok::kw_signed:
407 DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
408 break;
409 case tok::kw_unsigned:
410 DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
411 break;
412 case tok::kw_void:
413 DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
414 break;
415 case tok::kw_char:
416 DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
417 break;
418 case tok::kw_int:
419 DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
420 break;
421 case tok::kw_float:
422 DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
423 break;
424 case tok::kw_double:
425 DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
426 break;
427 case tok::kw_wchar_t:
428 DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
429 break;
430 case tok::kw_bool:
431 DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
432 break;
433
434 // GNU typeof support.
435 case tok::kw_typeof:
436 ParseTypeofSpecifier(DS);
437 DS.Finish(Diags, PP.getSourceManager(), getLang());
438 return;
439 }
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000440 if (Tok.is(tok::annot_qualtypename))
441 DS.SetRangeEnd(Tok.getAnnotationEndLoc());
442 else
443 DS.SetRangeEnd(Tok.getLocation());
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000444 ConsumeToken();
445 DS.Finish(Diags, PP.getSourceManager(), getLang());
446}
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000447
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000448/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
449/// [dcl.name]), which is a non-empty sequence of type-specifiers,
450/// e.g., "const short int". Note that the DeclSpec is *not* finished
451/// by parsing the type-specifier-seq, because these sequences are
452/// typically followed by some form of declarator. Returns true and
453/// emits diagnostics if this is not a type-specifier-seq, false
454/// otherwise.
455///
456/// type-specifier-seq: [C++ 8.1]
457/// type-specifier type-specifier-seq[opt]
458///
459bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
460 DS.SetRangeStart(Tok.getLocation());
461 const char *PrevSpec = 0;
462 int isInvalid = 0;
463
464 // Parse one or more of the type specifiers.
465 if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) {
466 Diag(Tok.getLocation(), diag::err_operator_missing_type_specifier);
467 return true;
468 }
Daniel Dunbarb90585c2008-11-08 04:28:37 +0000469 while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) ;
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000470
471 return false;
472}
473
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000474/// MaybeParseOperatorFunctionId - Attempts to parse a C++ overloaded
475/// operator name (C++ [over.oper]). If successful, returns the
476/// predefined identifier that corresponds to that overloaded
477/// operator. Otherwise, returns NULL and does not consume any tokens.
478///
479/// operator-function-id: [C++ 13.5]
480/// 'operator' operator
481///
482/// operator: one of
483/// new delete new[] delete[]
484/// + - * / % ^ & | ~
485/// ! = < > += -= *= /= %=
486/// ^= &= |= << >> >>= <<= == !=
487/// <= >= && || ++ -- , ->* ->
488/// () []
489IdentifierInfo *Parser::MaybeParseOperatorFunctionId() {
Argyrios Kyrtzidis9057a812008-11-07 15:54:02 +0000490 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000491
492 OverloadedOperatorKind Op = OO_None;
493 switch (NextToken().getKind()) {
494 case tok::kw_new:
495 ConsumeToken(); // 'operator'
496 ConsumeToken(); // 'new'
497 if (Tok.is(tok::l_square)) {
498 ConsumeBracket(); // '['
499 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
500 Op = OO_Array_New;
501 } else {
502 Op = OO_New;
503 }
504 return &PP.getIdentifierTable().getOverloadedOperator(Op);
505
506 case tok::kw_delete:
507 ConsumeToken(); // 'operator'
508 ConsumeToken(); // 'delete'
509 if (Tok.is(tok::l_square)) {
510 ConsumeBracket(); // '['
511 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
512 Op = OO_Array_Delete;
513 } else {
514 Op = OO_Delete;
515 }
516 return &PP.getIdentifierTable().getOverloadedOperator(Op);
517
518#define OVERLOADED_OPERATOR(Name,Spelling,Token) \
519 case tok::Token: Op = OO_##Name; break;
520#define OVERLOADED_OPERATOR_MULTI(Name,Spelling)
521#include "clang/Basic/OperatorKinds.def"
522
523 case tok::l_paren:
524 ConsumeToken(); // 'operator'
525 ConsumeParen(); // '('
526 ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
527 return &PP.getIdentifierTable().getOverloadedOperator(OO_Call);
528
529 case tok::l_square:
530 ConsumeToken(); // 'operator'
531 ConsumeBracket(); // '['
532 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
533 return &PP.getIdentifierTable().getOverloadedOperator(OO_Subscript);
534
535 default:
536 break;
537 }
538
539 if (Op == OO_None)
540 return 0;
541 else {
Argyrios Kyrtzidis9057a812008-11-07 15:54:02 +0000542 ConsumeToken(); // 'operator'
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000543 ConsumeAnyToken(); // the operator itself
544 return &PP.getIdentifierTable().getOverloadedOperator(Op);
545 }
546}
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000547
548/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
549/// which expresses the name of a user-defined conversion operator
550/// (C++ [class.conv.fct]p1). Returns the type that this operator is
551/// specifying a conversion for, or NULL if there was an error.
552///
553/// conversion-function-id: [C++ 12.3.2]
554/// operator conversion-type-id
555///
556/// conversion-type-id:
557/// type-specifier-seq conversion-declarator[opt]
558///
559/// conversion-declarator:
560/// ptr-operator conversion-declarator[opt]
561Parser::TypeTy *Parser::ParseConversionFunctionId() {
562 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
563 ConsumeToken(); // 'operator'
564
565 // Parse the type-specifier-seq.
566 DeclSpec DS;
567 if (ParseCXXTypeSpecifierSeq(DS))
568 return 0;
569
570 // Parse the conversion-declarator, which is merely a sequence of
571 // ptr-operators.
572 Declarator D(DS, Declarator::TypeNameContext);
573 ParseDeclaratorInternal(D, /*PtrOperator=*/true);
574
575 // Finish up the type.
576 Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
577 if (Result.isInvalid)
578 return 0;
579 else
580 return Result.Val;
581}