blob: 692e35df93de8f73334d366822878b6cf2cf1dda [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
Sebastian Redlc42e1182008-11-11 11:37:55 +0000219/// ParseCXXTypeid - This handles the C++ typeid expression.
220///
221/// postfix-expression: [C++ 5.2p1]
222/// 'typeid' '(' expression ')'
223/// 'typeid' '(' type-id ')'
224///
225Parser::ExprResult Parser::ParseCXXTypeid() {
226 assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
227
228 SourceLocation OpLoc = ConsumeToken();
229 SourceLocation LParenLoc = Tok.getLocation();
230 SourceLocation RParenLoc;
231
232 // typeid expressions are always parenthesized.
233 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
234 "typeid"))
235 return ExprResult(true);
236
237 Parser::ExprResult Result;
238
239 if (isTypeIdInParens()) {
240 TypeTy *Ty = ParseTypeName();
241
242 // Match the ')'.
243 MatchRHSPunctuation(tok::r_paren, LParenLoc);
244
245 if (!Ty)
246 return ExprResult(true);
247
248 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
249 Ty, RParenLoc);
250 } else {
251 Result = ParseExpression();
252
253 // Match the ')'.
254 if (Result.isInvalid)
255 SkipUntil(tok::r_paren);
256 else {
257 MatchRHSPunctuation(tok::r_paren, LParenLoc);
258
259 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
260 Result.Val, RParenLoc);
261 }
262 }
263
264 return Result;
265}
266
Reid Spencer5f016e22007-07-11 17:01:13 +0000267/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
268///
269/// boolean-literal: [C++ 2.13.5]
270/// 'true'
271/// 'false'
272Parser::ExprResult Parser::ParseCXXBoolLiteral() {
273 tok::TokenKind Kind = Tok.getKind();
Steve Naroff1b273c42007-09-16 14:56:35 +0000274 return Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind);
Reid Spencer5f016e22007-07-11 17:01:13 +0000275}
Chris Lattner50dd2892008-02-26 00:51:44 +0000276
277/// ParseThrowExpression - This handles the C++ throw expression.
278///
279/// throw-expression: [C++ 15]
280/// 'throw' assignment-expression[opt]
281Parser::ExprResult Parser::ParseThrowExpression() {
282 assert(Tok.is(tok::kw_throw) && "Not throw!");
Chris Lattner50dd2892008-02-26 00:51:44 +0000283 SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token.
Chris Lattner3e3d3102008-04-06 06:03:03 +0000284
Chris Lattner2a2819a2008-04-06 06:02:23 +0000285 // If the current token isn't the start of an assignment-expression,
286 // then the expression is not present. This handles things like:
287 // "C ? throw : (void)42", which is crazy but legal.
288 switch (Tok.getKind()) { // FIXME: move this predicate somewhere common.
289 case tok::semi:
290 case tok::r_paren:
291 case tok::r_square:
292 case tok::r_brace:
293 case tok::colon:
294 case tok::comma:
Chris Lattner50dd2892008-02-26 00:51:44 +0000295 return Actions.ActOnCXXThrow(ThrowLoc);
296
Chris Lattner2a2819a2008-04-06 06:02:23 +0000297 default:
Chris Lattner3e3d3102008-04-06 06:03:03 +0000298 ExprResult Expr = ParseAssignmentExpression();
Chris Lattner2a2819a2008-04-06 06:02:23 +0000299 if (Expr.isInvalid) return Expr;
300 return Actions.ActOnCXXThrow(ThrowLoc, Expr.Val);
301 }
Chris Lattner50dd2892008-02-26 00:51:44 +0000302}
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +0000303
304/// ParseCXXThis - This handles the C++ 'this' pointer.
305///
306/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
307/// a non-lvalue expression whose value is the address of the object for which
308/// the function is called.
309Parser::ExprResult Parser::ParseCXXThis() {
310 assert(Tok.is(tok::kw_this) && "Not 'this'!");
311 SourceLocation ThisLoc = ConsumeToken();
Argyrios Kyrtzidis289d7732008-08-16 19:34:46 +0000312 return Actions.ActOnCXXThis(ThisLoc);
Argyrios Kyrtzidis4cc18a42008-06-24 22:12:16 +0000313}
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000314
315/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
316/// Can be interpreted either as function-style casting ("int(x)")
317/// or class type construction ("ClassType(x,y,z)")
318/// or creation of a value-initialized type ("int()").
319///
320/// postfix-expression: [C++ 5.2p1]
321/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
322/// typename-specifier '(' expression-list[opt] ')' [TODO]
323///
324Parser::ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
325 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
326 TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
327
328 assert(Tok.is(tok::l_paren) && "Expected '('!");
329 SourceLocation LParenLoc = ConsumeParen();
330
331 ExprListTy Exprs;
332 CommaLocsTy CommaLocs;
333
334 if (Tok.isNot(tok::r_paren)) {
335 if (ParseExpressionList(Exprs, CommaLocs)) {
336 SkipUntil(tok::r_paren);
337 return ExprResult(true);
338 }
339 }
340
341 // Match the ')'.
342 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
343
344 assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
345 "Unexpected number of commas!");
346 return Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
347 LParenLoc,
348 &Exprs[0], Exprs.size(),
349 &CommaLocs[0], RParenLoc);
350}
351
Argyrios Kyrtzidis71b914b2008-09-09 20:38:47 +0000352/// ParseCXXCondition - if/switch/while/for condition expression.
353///
354/// condition:
355/// expression
356/// type-specifier-seq declarator '=' assignment-expression
357/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
358/// '=' assignment-expression
359///
360Parser::ExprResult Parser::ParseCXXCondition() {
Argyrios Kyrtzidisa8a45982008-10-05 15:03:47 +0000361 if (!isCXXConditionDeclaration())
Argyrios Kyrtzidis71b914b2008-09-09 20:38:47 +0000362 return ParseExpression(); // expression
363
364 SourceLocation StartLoc = Tok.getLocation();
365
366 // type-specifier-seq
367 DeclSpec DS;
368 ParseSpecifierQualifierList(DS);
369
370 // declarator
371 Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
372 ParseDeclarator(DeclaratorInfo);
373
374 // simple-asm-expr[opt]
375 if (Tok.is(tok::kw_asm)) {
376 ExprResult AsmLabel = ParseSimpleAsm();
377 if (AsmLabel.isInvalid) {
378 SkipUntil(tok::semi);
379 return true;
380 }
381 DeclaratorInfo.setAsmLabel(AsmLabel.Val);
382 }
383
384 // If attributes are present, parse them.
385 if (Tok.is(tok::kw___attribute))
386 DeclaratorInfo.AddAttributes(ParseAttributes());
387
388 // '=' assignment-expression
389 if (Tok.isNot(tok::equal))
390 return Diag(Tok, diag::err_expected_equal_after_declarator);
391 SourceLocation EqualLoc = ConsumeToken();
392 ExprResult AssignExpr = ParseAssignmentExpression();
393 if (AssignExpr.isInvalid)
394 return true;
395
396 return Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
397 DeclaratorInfo,
398 EqualLoc, AssignExpr.Val);
399}
400
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000401/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
402/// This should only be called when the current token is known to be part of
403/// simple-type-specifier.
404///
405/// simple-type-specifier:
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000406/// '::'[opt] nested-name-specifier[opt] type-name
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000407/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
408/// char
409/// wchar_t
410/// bool
411/// short
412/// int
413/// long
414/// signed
415/// unsigned
416/// float
417/// double
418/// void
419/// [GNU] typeof-specifier
420/// [C++0x] auto [TODO]
421///
422/// type-name:
423/// class-name
424/// enum-name
425/// typedef-name
426///
427void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000428 // Annotate typenames and C++ scope specifiers.
429 TryAnnotateTypeOrScopeToken();
430
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000431 DS.SetRangeStart(Tok.getLocation());
432 const char *PrevSpec;
433 SourceLocation Loc = Tok.getLocation();
434
435 switch (Tok.getKind()) {
436 default:
437 assert(0 && "Not a simple-type-specifier token!");
438 abort();
439
440 // type-name
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000441 case tok::annot_qualtypename: {
442 DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
443 Tok.getAnnotationValue());
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000444 break;
445 }
446
447 // builtin types
448 case tok::kw_short:
449 DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
450 break;
451 case tok::kw_long:
452 DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
453 break;
454 case tok::kw_signed:
455 DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
456 break;
457 case tok::kw_unsigned:
458 DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
459 break;
460 case tok::kw_void:
461 DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
462 break;
463 case tok::kw_char:
464 DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
465 break;
466 case tok::kw_int:
467 DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
468 break;
469 case tok::kw_float:
470 DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
471 break;
472 case tok::kw_double:
473 DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
474 break;
475 case tok::kw_wchar_t:
476 DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
477 break;
478 case tok::kw_bool:
479 DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
480 break;
481
482 // GNU typeof support.
483 case tok::kw_typeof:
484 ParseTypeofSpecifier(DS);
485 DS.Finish(Diags, PP.getSourceManager(), getLang());
486 return;
487 }
Argyrios Kyrtzidiseb83ecd2008-11-08 16:45:02 +0000488 if (Tok.is(tok::annot_qualtypename))
489 DS.SetRangeEnd(Tok.getAnnotationEndLoc());
490 else
491 DS.SetRangeEnd(Tok.getLocation());
Argyrios Kyrtzidis987a14b2008-08-22 15:38:55 +0000492 ConsumeToken();
493 DS.Finish(Diags, PP.getSourceManager(), getLang());
494}
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000495
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000496/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
497/// [dcl.name]), which is a non-empty sequence of type-specifiers,
498/// e.g., "const short int". Note that the DeclSpec is *not* finished
499/// by parsing the type-specifier-seq, because these sequences are
500/// typically followed by some form of declarator. Returns true and
501/// emits diagnostics if this is not a type-specifier-seq, false
502/// otherwise.
503///
504/// type-specifier-seq: [C++ 8.1]
505/// type-specifier type-specifier-seq[opt]
506///
507bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
508 DS.SetRangeStart(Tok.getLocation());
509 const char *PrevSpec = 0;
510 int isInvalid = 0;
511
512 // Parse one or more of the type specifiers.
513 if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) {
514 Diag(Tok.getLocation(), diag::err_operator_missing_type_specifier);
515 return true;
516 }
Daniel Dunbarb90585c2008-11-08 04:28:37 +0000517 while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) ;
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000518
519 return false;
520}
521
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000522/// MaybeParseOperatorFunctionId - Attempts to parse a C++ overloaded
523/// operator name (C++ [over.oper]). If successful, returns the
524/// predefined identifier that corresponds to that overloaded
525/// operator. Otherwise, returns NULL and does not consume any tokens.
526///
527/// operator-function-id: [C++ 13.5]
528/// 'operator' operator
529///
530/// operator: one of
531/// new delete new[] delete[]
532/// + - * / % ^ & | ~
533/// ! = < > += -= *= /= %=
534/// ^= &= |= << >> >>= <<= == !=
535/// <= >= && || ++ -- , ->* ->
536/// () []
537IdentifierInfo *Parser::MaybeParseOperatorFunctionId() {
Argyrios Kyrtzidis9057a812008-11-07 15:54:02 +0000538 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000539
540 OverloadedOperatorKind Op = OO_None;
541 switch (NextToken().getKind()) {
542 case tok::kw_new:
543 ConsumeToken(); // 'operator'
544 ConsumeToken(); // 'new'
545 if (Tok.is(tok::l_square)) {
546 ConsumeBracket(); // '['
547 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
548 Op = OO_Array_New;
549 } else {
550 Op = OO_New;
551 }
552 return &PP.getIdentifierTable().getOverloadedOperator(Op);
553
554 case tok::kw_delete:
555 ConsumeToken(); // 'operator'
556 ConsumeToken(); // 'delete'
557 if (Tok.is(tok::l_square)) {
558 ConsumeBracket(); // '['
559 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
560 Op = OO_Array_Delete;
561 } else {
562 Op = OO_Delete;
563 }
564 return &PP.getIdentifierTable().getOverloadedOperator(Op);
565
Douglas Gregor02bcd4c2008-11-10 13:38:07 +0000566#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000567 case tok::Token: Op = OO_##Name; break;
Douglas Gregor02bcd4c2008-11-10 13:38:07 +0000568#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000569#include "clang/Basic/OperatorKinds.def"
570
571 case tok::l_paren:
572 ConsumeToken(); // 'operator'
573 ConsumeParen(); // '('
574 ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
575 return &PP.getIdentifierTable().getOverloadedOperator(OO_Call);
576
577 case tok::l_square:
578 ConsumeToken(); // 'operator'
579 ConsumeBracket(); // '['
580 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
581 return &PP.getIdentifierTable().getOverloadedOperator(OO_Subscript);
582
583 default:
584 break;
585 }
586
587 if (Op == OO_None)
588 return 0;
589 else {
Argyrios Kyrtzidis9057a812008-11-07 15:54:02 +0000590 ConsumeToken(); // 'operator'
Douglas Gregor1cd1b1e2008-11-06 22:13:31 +0000591 ConsumeAnyToken(); // the operator itself
592 return &PP.getIdentifierTable().getOverloadedOperator(Op);
593 }
594}
Douglas Gregor2f1bc522008-11-07 20:08:42 +0000595
596/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
597/// which expresses the name of a user-defined conversion operator
598/// (C++ [class.conv.fct]p1). Returns the type that this operator is
599/// specifying a conversion for, or NULL if there was an error.
600///
601/// conversion-function-id: [C++ 12.3.2]
602/// operator conversion-type-id
603///
604/// conversion-type-id:
605/// type-specifier-seq conversion-declarator[opt]
606///
607/// conversion-declarator:
608/// ptr-operator conversion-declarator[opt]
609Parser::TypeTy *Parser::ParseConversionFunctionId() {
610 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
611 ConsumeToken(); // 'operator'
612
613 // Parse the type-specifier-seq.
614 DeclSpec DS;
615 if (ParseCXXTypeSpecifierSeq(DS))
616 return 0;
617
618 // Parse the conversion-declarator, which is merely a sequence of
619 // ptr-operators.
620 Declarator D(DS, Declarator::TypeNameContext);
621 ParseDeclaratorInternal(D, /*PtrOperator=*/true);
622
623 // Finish up the type.
624 Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
625 if (Result.isInvalid)
626 return 0;
627 else
628 return Result.Val;
629}