ParseExprCXX.cpp revision 809070a886684cb5b92eb0e00a6581ab1fa6b17a
1//===--- ParseExprCXX.cpp - C++ Expression 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 Expression parsing implementation for C++.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/Parse/ParseDiagnostic.h"
15#include "clang/Parse/Parser.h"
16#include "clang/Parse/DeclSpec.h"
17#include "AstGuard.h"
18using namespace clang;
19
20/// ParseOptionalCXXScopeSpecifier - Parse global scope or
21/// nested-name-specifier if present.  Returns true if a nested-name-specifier
22/// was parsed from the token stream.  Note that this routine will not parse
23/// ::new or ::delete, it will just leave them in the token stream.
24///
25///       '::'[opt] nested-name-specifier
26///       '::'
27///
28///       nested-name-specifier:
29///         type-name '::'
30///         namespace-name '::'
31///         nested-name-specifier identifier '::'
32///         nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
33///
34bool Parser::ParseOptionalCXXScopeSpecifier(CXXScopeSpec &SS) {
35  assert(getLang().CPlusPlus &&
36         "Call sites of this function should be guarded by checking for C++");
37
38  if (Tok.is(tok::annot_cxxscope)) {
39    SS.setScopeRep(Tok.getAnnotationValue());
40    SS.setRange(Tok.getAnnotationRange());
41    ConsumeToken();
42    return true;
43  }
44
45  if (Tok.is(tok::coloncolon)) {
46    // ::new and ::delete aren't nested-name-specifiers.
47    tok::TokenKind NextKind = NextToken().getKind();
48    if (NextKind == tok::kw_new || NextKind == tok::kw_delete)
49      return false;
50
51    // '::' - Global scope qualifier.
52    SourceLocation CCLoc = ConsumeToken();
53    SS.setBeginLoc(CCLoc);
54    SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
55    SS.setEndLoc(CCLoc);
56  } else if (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
57    SS.setBeginLoc(Tok.getLocation());
58  } else {
59    // Not a CXXScopeSpecifier.
60    return false;
61  }
62
63  // nested-name-specifier:
64  //   type-name '::'
65  //   namespace-name '::'
66  //   nested-name-specifier identifier '::'
67  //   nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
68  while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
69    IdentifierInfo *II = Tok.getIdentifierInfo();
70    SourceLocation IdLoc = ConsumeToken();
71    assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
72    SourceLocation CCLoc = ConsumeToken();
73    if (SS.isInvalid())
74      continue;
75
76    SS.setScopeRep(
77         Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
78    SS.setEndLoc(CCLoc);
79  }
80
81  return true;
82}
83
84/// ParseCXXIdExpression - Handle id-expression.
85///
86///       id-expression:
87///         unqualified-id
88///         qualified-id
89///
90///       unqualified-id:
91///         identifier
92///         operator-function-id
93///         conversion-function-id                [TODO]
94///         '~' class-name                        [TODO]
95///         template-id                           [TODO]
96///
97///       qualified-id:
98///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
99///         '::' identifier
100///         '::' operator-function-id
101///         '::' template-id                      [TODO]
102///
103///       nested-name-specifier:
104///         type-name '::'
105///         namespace-name '::'
106///         nested-name-specifier identifier '::'
107///         nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
108///
109/// NOTE: The standard specifies that, for qualified-id, the parser does not
110/// expect:
111///
112///   '::' conversion-function-id
113///   '::' '~' class-name
114///
115/// This may cause a slight inconsistency on diagnostics:
116///
117/// class C {};
118/// namespace A {}
119/// void f() {
120///   :: A :: ~ C(); // Some Sema error about using destructor with a
121///                  // namespace.
122///   :: ~ C(); // Some Parser error like 'unexpected ~'.
123/// }
124///
125/// We simplify the parser a bit and make it work like:
126///
127///       qualified-id:
128///         '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
129///         '::' unqualified-id
130///
131/// That way Sema can handle and report similar errors for namespaces and the
132/// global scope.
133///
134/// The isAddressOfOperand parameter indicates that this id-expression is a
135/// direct operand of the address-of operator. This is, besides member contexts,
136/// the only place where a qualified-id naming a non-static class member may
137/// appear.
138///
139Parser::OwningExprResult Parser::ParseCXXIdExpression(bool isAddressOfOperand) {
140  // qualified-id:
141  //   '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
142  //   '::' unqualified-id
143  //
144  CXXScopeSpec SS;
145  ParseOptionalCXXScopeSpecifier(SS);
146
147  // unqualified-id:
148  //   identifier
149  //   operator-function-id
150  //   conversion-function-id
151  //   '~' class-name                        [TODO]
152  //   template-id                           [TODO]
153  //
154  switch (Tok.getKind()) {
155  default:
156    return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
157
158  case tok::identifier: {
159    // Consume the identifier so that we can see if it is followed by a '('.
160    IdentifierInfo &II = *Tok.getIdentifierInfo();
161    SourceLocation L = ConsumeToken();
162    return Actions.ActOnIdentifierExpr(CurScope, L, II, Tok.is(tok::l_paren),
163                                       &SS, isAddressOfOperand);
164  }
165
166  case tok::kw_operator: {
167    SourceLocation OperatorLoc = Tok.getLocation();
168    if (OverloadedOperatorKind Op = TryParseOperatorFunctionId())
169      return Actions.ActOnCXXOperatorFunctionIdExpr(
170                       CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS,
171                       isAddressOfOperand);
172    if (TypeTy *Type = ParseConversionFunctionId())
173      return Actions.ActOnCXXConversionFunctionExpr(CurScope, OperatorLoc, Type,
174                                                    Tok.is(tok::l_paren), SS,
175                                                    isAddressOfOperand);
176
177    // We already complained about a bad conversion-function-id,
178    // above.
179    return ExprError();
180  }
181
182  } // switch.
183
184  assert(0 && "The switch was supposed to take care everything.");
185}
186
187/// ParseCXXCasts - This handles the various ways to cast expressions to another
188/// type.
189///
190///       postfix-expression: [C++ 5.2p1]
191///         'dynamic_cast' '<' type-name '>' '(' expression ')'
192///         'static_cast' '<' type-name '>' '(' expression ')'
193///         'reinterpret_cast' '<' type-name '>' '(' expression ')'
194///         'const_cast' '<' type-name '>' '(' expression ')'
195///
196Parser::OwningExprResult Parser::ParseCXXCasts() {
197  tok::TokenKind Kind = Tok.getKind();
198  const char *CastName = 0;     // For error messages
199
200  switch (Kind) {
201  default: assert(0 && "Unknown C++ cast!"); abort();
202  case tok::kw_const_cast:       CastName = "const_cast";       break;
203  case tok::kw_dynamic_cast:     CastName = "dynamic_cast";     break;
204  case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
205  case tok::kw_static_cast:      CastName = "static_cast";      break;
206  }
207
208  SourceLocation OpLoc = ConsumeToken();
209  SourceLocation LAngleBracketLoc = Tok.getLocation();
210
211  if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
212    return ExprError();
213
214  TypeResult CastTy = ParseTypeName();
215  SourceLocation RAngleBracketLoc = Tok.getLocation();
216
217  if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
218    return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
219
220  SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
221
222  if (Tok.isNot(tok::l_paren))
223    return ExprError(Diag(Tok, diag::err_expected_lparen_after) << CastName);
224
225  OwningExprResult Result(ParseSimpleParenExpression(RParenLoc));
226
227  if (!Result.isInvalid() && !CastTy.isInvalid())
228    Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
229                                       LAngleBracketLoc, CastTy.get(),
230                                       RAngleBracketLoc,
231                                       LParenLoc, Result.release(), RParenLoc);
232
233  return move(Result);
234}
235
236/// ParseCXXTypeid - This handles the C++ typeid expression.
237///
238///       postfix-expression: [C++ 5.2p1]
239///         'typeid' '(' expression ')'
240///         'typeid' '(' type-id ')'
241///
242Parser::OwningExprResult Parser::ParseCXXTypeid() {
243  assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
244
245  SourceLocation OpLoc = ConsumeToken();
246  SourceLocation LParenLoc = Tok.getLocation();
247  SourceLocation RParenLoc;
248
249  // typeid expressions are always parenthesized.
250  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
251      "typeid"))
252    return ExprError();
253
254  OwningExprResult Result(Actions);
255
256  if (isTypeIdInParens()) {
257    TypeResult Ty = ParseTypeName();
258
259    // Match the ')'.
260    MatchRHSPunctuation(tok::r_paren, LParenLoc);
261
262    if (Ty.isInvalid())
263      return ExprError();
264
265    Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
266                                    Ty.get(), RParenLoc);
267  } else {
268    Result = ParseExpression();
269
270    // Match the ')'.
271    if (Result.isInvalid())
272      SkipUntil(tok::r_paren);
273    else {
274      MatchRHSPunctuation(tok::r_paren, LParenLoc);
275
276      Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
277                                      Result.release(), RParenLoc);
278    }
279  }
280
281  return move(Result);
282}
283
284/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
285///
286///       boolean-literal: [C++ 2.13.5]
287///         'true'
288///         'false'
289Parser::OwningExprResult Parser::ParseCXXBoolLiteral() {
290  tok::TokenKind Kind = Tok.getKind();
291  return Owned(Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind));
292}
293
294/// ParseThrowExpression - This handles the C++ throw expression.
295///
296///       throw-expression: [C++ 15]
297///         'throw' assignment-expression[opt]
298Parser::OwningExprResult Parser::ParseThrowExpression() {
299  assert(Tok.is(tok::kw_throw) && "Not throw!");
300  SourceLocation ThrowLoc = ConsumeToken();           // Eat the throw token.
301
302  // If the current token isn't the start of an assignment-expression,
303  // then the expression is not present.  This handles things like:
304  //   "C ? throw : (void)42", which is crazy but legal.
305  switch (Tok.getKind()) {  // FIXME: move this predicate somewhere common.
306  case tok::semi:
307  case tok::r_paren:
308  case tok::r_square:
309  case tok::r_brace:
310  case tok::colon:
311  case tok::comma:
312    return Owned(Actions.ActOnCXXThrow(ThrowLoc));
313
314  default:
315    OwningExprResult Expr(ParseAssignmentExpression());
316    if (Expr.isInvalid()) return move(Expr);
317    return Owned(Actions.ActOnCXXThrow(ThrowLoc, Expr.release()));
318  }
319}
320
321/// ParseCXXThis - This handles the C++ 'this' pointer.
322///
323/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
324/// a non-lvalue expression whose value is the address of the object for which
325/// the function is called.
326Parser::OwningExprResult Parser::ParseCXXThis() {
327  assert(Tok.is(tok::kw_this) && "Not 'this'!");
328  SourceLocation ThisLoc = ConsumeToken();
329  return Owned(Actions.ActOnCXXThis(ThisLoc));
330}
331
332/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
333/// Can be interpreted either as function-style casting ("int(x)")
334/// or class type construction ("ClassType(x,y,z)")
335/// or creation of a value-initialized type ("int()").
336///
337///       postfix-expression: [C++ 5.2p1]
338///         simple-type-specifier '(' expression-list[opt] ')'      [C++ 5.2.3]
339///         typename-specifier '(' expression-list[opt] ')'         [TODO]
340///
341Parser::OwningExprResult
342Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
343  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
344  TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).get();
345
346  assert(Tok.is(tok::l_paren) && "Expected '('!");
347  SourceLocation LParenLoc = ConsumeParen();
348
349  ExprVector Exprs(Actions);
350  CommaLocsTy CommaLocs;
351
352  if (Tok.isNot(tok::r_paren)) {
353    if (ParseExpressionList(Exprs, CommaLocs)) {
354      SkipUntil(tok::r_paren);
355      return ExprError();
356    }
357  }
358
359  // Match the ')'.
360  SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
361
362  assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
363         "Unexpected number of commas!");
364  return Owned(Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
365                                                 LParenLoc,
366                                                 Exprs.take(), Exprs.size(),
367                                                 &CommaLocs[0], RParenLoc));
368}
369
370/// ParseCXXCondition - if/switch/while/for condition expression.
371///
372///       condition:
373///         expression
374///         type-specifier-seq declarator '=' assignment-expression
375/// [GNU]   type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
376///             '=' assignment-expression
377///
378Parser::OwningExprResult Parser::ParseCXXCondition() {
379  if (!isCXXConditionDeclaration())
380    return ParseExpression(); // expression
381
382  SourceLocation StartLoc = Tok.getLocation();
383
384  // type-specifier-seq
385  DeclSpec DS;
386  ParseSpecifierQualifierList(DS);
387
388  // declarator
389  Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
390  ParseDeclarator(DeclaratorInfo);
391
392  // simple-asm-expr[opt]
393  if (Tok.is(tok::kw_asm)) {
394    SourceLocation Loc;
395    OwningExprResult AsmLabel(ParseSimpleAsm(&Loc));
396    if (AsmLabel.isInvalid()) {
397      SkipUntil(tok::semi);
398      return ExprError();
399    }
400    DeclaratorInfo.setAsmLabel(AsmLabel.release());
401    DeclaratorInfo.SetRangeEnd(Loc);
402  }
403
404  // If attributes are present, parse them.
405  if (Tok.is(tok::kw___attribute)) {
406    SourceLocation Loc;
407    AttributeList *AttrList = ParseAttributes(&Loc);
408    DeclaratorInfo.AddAttributes(AttrList, Loc);
409  }
410
411  // '=' assignment-expression
412  if (Tok.isNot(tok::equal))
413    return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
414  SourceLocation EqualLoc = ConsumeToken();
415  OwningExprResult AssignExpr(ParseAssignmentExpression());
416  if (AssignExpr.isInvalid())
417    return ExprError();
418
419  return Owned(Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
420                                                        DeclaratorInfo,EqualLoc,
421                                                        AssignExpr.release()));
422}
423
424/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
425/// This should only be called when the current token is known to be part of
426/// simple-type-specifier.
427///
428///       simple-type-specifier:
429///         '::'[opt] nested-name-specifier[opt] type-name
430///         '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
431///         char
432///         wchar_t
433///         bool
434///         short
435///         int
436///         long
437///         signed
438///         unsigned
439///         float
440///         double
441///         void
442/// [GNU]   typeof-specifier
443/// [C++0x] auto               [TODO]
444///
445///       type-name:
446///         class-name
447///         enum-name
448///         typedef-name
449///
450void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
451  DS.SetRangeStart(Tok.getLocation());
452  const char *PrevSpec;
453  SourceLocation Loc = Tok.getLocation();
454
455  switch (Tok.getKind()) {
456  case tok::identifier:   // foo::bar
457  case tok::coloncolon:   // ::foo::bar
458    assert(0 && "Annotation token should already be formed!");
459  default:
460    assert(0 && "Not a simple-type-specifier token!");
461    abort();
462
463  // type-name
464  case tok::annot_typename: {
465    DS.SetTypeSpecType(DeclSpec::TST_typename, Loc, PrevSpec,
466                       Tok.getAnnotationValue());
467    break;
468  }
469
470  // builtin types
471  case tok::kw_short:
472    DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
473    break;
474  case tok::kw_long:
475    DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
476    break;
477  case tok::kw_signed:
478    DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
479    break;
480  case tok::kw_unsigned:
481    DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
482    break;
483  case tok::kw_void:
484    DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
485    break;
486  case tok::kw_char:
487    DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
488    break;
489  case tok::kw_int:
490    DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
491    break;
492  case tok::kw_float:
493    DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
494    break;
495  case tok::kw_double:
496    DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
497    break;
498  case tok::kw_wchar_t:
499    DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
500    break;
501  case tok::kw_bool:
502    DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
503    break;
504
505  // GNU typeof support.
506  case tok::kw_typeof:
507    ParseTypeofSpecifier(DS);
508    DS.Finish(Diags, PP.getSourceManager(), getLang());
509    return;
510  }
511  if (Tok.is(tok::annot_typename))
512    DS.SetRangeEnd(Tok.getAnnotationEndLoc());
513  else
514    DS.SetRangeEnd(Tok.getLocation());
515  ConsumeToken();
516  DS.Finish(Diags, PP.getSourceManager(), getLang());
517}
518
519/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
520/// [dcl.name]), which is a non-empty sequence of type-specifiers,
521/// e.g., "const short int". Note that the DeclSpec is *not* finished
522/// by parsing the type-specifier-seq, because these sequences are
523/// typically followed by some form of declarator. Returns true and
524/// emits diagnostics if this is not a type-specifier-seq, false
525/// otherwise.
526///
527///   type-specifier-seq: [C++ 8.1]
528///     type-specifier type-specifier-seq[opt]
529///
530bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
531  DS.SetRangeStart(Tok.getLocation());
532  const char *PrevSpec = 0;
533  int isInvalid = 0;
534
535  // Parse one or more of the type specifiers.
536  if (!ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) {
537    Diag(Tok, diag::err_operator_missing_type_specifier);
538    return true;
539  }
540
541  while (ParseOptionalTypeSpecifier(DS, isInvalid, PrevSpec)) ;
542
543  return false;
544}
545
546/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
547/// operator name (C++ [over.oper]). If successful, returns the
548/// predefined identifier that corresponds to that overloaded
549/// operator. Otherwise, returns NULL and does not consume any tokens.
550///
551///       operator-function-id: [C++ 13.5]
552///         'operator' operator
553///
554/// operator: one of
555///            new   delete  new[]   delete[]
556///            +     -    *  /    %  ^    &   |   ~
557///            !     =    <  >    += -=   *=  /=  %=
558///            ^=    &=   |= <<   >> >>= <<=  ==  !=
559///            <=    >=   && ||   ++ --   ,   ->* ->
560///            ()    []
561OverloadedOperatorKind
562Parser::TryParseOperatorFunctionId(SourceLocation *EndLoc) {
563  assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
564  SourceLocation Loc;
565
566  OverloadedOperatorKind Op = OO_None;
567  switch (NextToken().getKind()) {
568  case tok::kw_new:
569    ConsumeToken(); // 'operator'
570    Loc = ConsumeToken(); // 'new'
571    if (Tok.is(tok::l_square)) {
572      ConsumeBracket(); // '['
573      Loc = Tok.getLocation();
574      ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
575      Op = OO_Array_New;
576    } else {
577      Op = OO_New;
578    }
579    if (EndLoc)
580      *EndLoc = Loc;
581    return Op;
582
583  case tok::kw_delete:
584    ConsumeToken(); // 'operator'
585    Loc = ConsumeToken(); // 'delete'
586    if (Tok.is(tok::l_square)) {
587      ConsumeBracket(); // '['
588      Loc = Tok.getLocation();
589      ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
590      Op = OO_Array_Delete;
591    } else {
592      Op = OO_Delete;
593    }
594    if (EndLoc)
595      *EndLoc = Loc;
596    return Op;
597
598#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly)  \
599    case tok::Token:  Op = OO_##Name; break;
600#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
601#include "clang/Basic/OperatorKinds.def"
602
603  case tok::l_paren:
604    ConsumeToken(); // 'operator'
605    ConsumeParen(); // '('
606    Loc = Tok.getLocation();
607    ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
608    if (EndLoc)
609      *EndLoc = Loc;
610    return OO_Call;
611
612  case tok::l_square:
613    ConsumeToken(); // 'operator'
614    ConsumeBracket(); // '['
615    Loc = Tok.getLocation();
616    ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
617    if (EndLoc)
618      *EndLoc = Loc;
619    return OO_Subscript;
620
621  default:
622    return OO_None;
623  }
624
625  ConsumeToken(); // 'operator'
626  Loc = ConsumeAnyToken(); // the operator itself
627  if (EndLoc)
628    *EndLoc = Loc;
629  return Op;
630}
631
632/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
633/// which expresses the name of a user-defined conversion operator
634/// (C++ [class.conv.fct]p1). Returns the type that this operator is
635/// specifying a conversion for, or NULL if there was an error.
636///
637///        conversion-function-id: [C++ 12.3.2]
638///                   operator conversion-type-id
639///
640///        conversion-type-id:
641///                   type-specifier-seq conversion-declarator[opt]
642///
643///        conversion-declarator:
644///                   ptr-operator conversion-declarator[opt]
645Parser::TypeTy *Parser::ParseConversionFunctionId(SourceLocation *EndLoc) {
646  assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
647  ConsumeToken(); // 'operator'
648
649  // Parse the type-specifier-seq.
650  DeclSpec DS;
651  if (ParseCXXTypeSpecifierSeq(DS))
652    return 0;
653
654  // Parse the conversion-declarator, which is merely a sequence of
655  // ptr-operators.
656  Declarator D(DS, Declarator::TypeNameContext);
657  ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
658  if (EndLoc)
659    *EndLoc = D.getSourceRange().getEnd();
660
661  // Finish up the type.
662  Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
663  if (Result.isInvalid())
664    return 0;
665  else
666    return Result.get();
667}
668
669/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
670/// memory in a typesafe manner and call constructors.
671///
672/// This method is called to parse the new expression after the optional :: has
673/// been already parsed.  If the :: was present, "UseGlobal" is true and "Start"
674/// is its location.  Otherwise, "Start" is the location of the 'new' token.
675///
676///        new-expression:
677///                   '::'[opt] 'new' new-placement[opt] new-type-id
678///                                     new-initializer[opt]
679///                   '::'[opt] 'new' new-placement[opt] '(' type-id ')'
680///                                     new-initializer[opt]
681///
682///        new-placement:
683///                   '(' expression-list ')'
684///
685///        new-type-id:
686///                   type-specifier-seq new-declarator[opt]
687///
688///        new-declarator:
689///                   ptr-operator new-declarator[opt]
690///                   direct-new-declarator
691///
692///        new-initializer:
693///                   '(' expression-list[opt] ')'
694/// [C++0x]           braced-init-list                                   [TODO]
695///
696Parser::OwningExprResult
697Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
698  assert(Tok.is(tok::kw_new) && "expected 'new' token");
699  ConsumeToken();   // Consume 'new'
700
701  // A '(' now can be a new-placement or the '(' wrapping the type-id in the
702  // second form of new-expression. It can't be a new-type-id.
703
704  ExprVector PlacementArgs(Actions);
705  SourceLocation PlacementLParen, PlacementRParen;
706
707  bool ParenTypeId;
708  DeclSpec DS;
709  Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
710  if (Tok.is(tok::l_paren)) {
711    // If it turns out to be a placement, we change the type location.
712    PlacementLParen = ConsumeParen();
713    if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
714      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
715      return ExprError();
716    }
717
718    PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
719    if (PlacementRParen.isInvalid()) {
720      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
721      return ExprError();
722    }
723
724    if (PlacementArgs.empty()) {
725      // Reset the placement locations. There was no placement.
726      PlacementLParen = PlacementRParen = SourceLocation();
727      ParenTypeId = true;
728    } else {
729      // We still need the type.
730      if (Tok.is(tok::l_paren)) {
731        SourceLocation LParen = ConsumeParen();
732        ParseSpecifierQualifierList(DS);
733        DeclaratorInfo.SetSourceRange(DS.getSourceRange());
734        ParseDeclarator(DeclaratorInfo);
735        MatchRHSPunctuation(tok::r_paren, LParen);
736        ParenTypeId = true;
737      } else {
738        if (ParseCXXTypeSpecifierSeq(DS))
739          DeclaratorInfo.setInvalidType(true);
740        else {
741          DeclaratorInfo.SetSourceRange(DS.getSourceRange());
742          ParseDeclaratorInternal(DeclaratorInfo,
743                                  &Parser::ParseDirectNewDeclarator);
744        }
745        ParenTypeId = false;
746      }
747    }
748  } else {
749    // A new-type-id is a simplified type-id, where essentially the
750    // direct-declarator is replaced by a direct-new-declarator.
751    if (ParseCXXTypeSpecifierSeq(DS))
752      DeclaratorInfo.setInvalidType(true);
753    else {
754      DeclaratorInfo.SetSourceRange(DS.getSourceRange());
755      ParseDeclaratorInternal(DeclaratorInfo,
756                              &Parser::ParseDirectNewDeclarator);
757    }
758    ParenTypeId = false;
759  }
760  if (DeclaratorInfo.getInvalidType()) {
761    SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
762    return ExprError();
763  }
764
765  ExprVector ConstructorArgs(Actions);
766  SourceLocation ConstructorLParen, ConstructorRParen;
767
768  if (Tok.is(tok::l_paren)) {
769    ConstructorLParen = ConsumeParen();
770    if (Tok.isNot(tok::r_paren)) {
771      CommaLocsTy CommaLocs;
772      if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
773        SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
774        return ExprError();
775      }
776    }
777    ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
778    if (ConstructorRParen.isInvalid()) {
779      SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
780      return ExprError();
781    }
782  }
783
784  return Owned(Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
785                                   PlacementArgs.take(), PlacementArgs.size(),
786                                   PlacementRParen, ParenTypeId, DeclaratorInfo,
787                                   ConstructorLParen, ConstructorArgs.take(),
788                                   ConstructorArgs.size(), ConstructorRParen));
789}
790
791/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
792/// passed to ParseDeclaratorInternal.
793///
794///        direct-new-declarator:
795///                   '[' expression ']'
796///                   direct-new-declarator '[' constant-expression ']'
797///
798void Parser::ParseDirectNewDeclarator(Declarator &D) {
799  // Parse the array dimensions.
800  bool first = true;
801  while (Tok.is(tok::l_square)) {
802    SourceLocation LLoc = ConsumeBracket();
803    OwningExprResult Size(first ? ParseExpression()
804                                : ParseConstantExpression());
805    if (Size.isInvalid()) {
806      // Recover
807      SkipUntil(tok::r_square);
808      return;
809    }
810    first = false;
811
812    SourceLocation RLoc = MatchRHSPunctuation(tok::r_square, LLoc);
813    D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false,
814                                            Size.release(), LLoc),
815                  RLoc);
816
817    if (RLoc.isInvalid())
818      return;
819  }
820}
821
822/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id.
823/// This ambiguity appears in the syntax of the C++ new operator.
824///
825///        new-expression:
826///                   '::'[opt] 'new' new-placement[opt] '(' type-id ')'
827///                                     new-initializer[opt]
828///
829///        new-placement:
830///                   '(' expression-list ')'
831///
832bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
833                                         Declarator &D) {
834  // The '(' was already consumed.
835  if (isTypeIdInParens()) {
836    ParseSpecifierQualifierList(D.getMutableDeclSpec());
837    D.SetSourceRange(D.getDeclSpec().getSourceRange());
838    ParseDeclarator(D);
839    return D.getInvalidType();
840  }
841
842  // It's not a type, it has to be an expression list.
843  // Discard the comma locations - ActOnCXXNew has enough parameters.
844  CommaLocsTy CommaLocs;
845  return ParseExpressionList(PlacementArgs, CommaLocs);
846}
847
848/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
849/// to free memory allocated by new.
850///
851/// This method is called to parse the 'delete' expression after the optional
852/// '::' has been already parsed.  If the '::' was present, "UseGlobal" is true
853/// and "Start" is its location.  Otherwise, "Start" is the location of the
854/// 'delete' token.
855///
856///        delete-expression:
857///                   '::'[opt] 'delete' cast-expression
858///                   '::'[opt] 'delete' '[' ']' cast-expression
859Parser::OwningExprResult
860Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
861  assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
862  ConsumeToken(); // Consume 'delete'
863
864  // Array delete?
865  bool ArrayDelete = false;
866  if (Tok.is(tok::l_square)) {
867    ArrayDelete = true;
868    SourceLocation LHS = ConsumeBracket();
869    SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
870    if (RHS.isInvalid())
871      return ExprError();
872  }
873
874  OwningExprResult Operand(ParseCastExpression(false));
875  if (Operand.isInvalid())
876    return move(Operand);
877
878  return Owned(Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete,
879                                      Operand.release()));
880}
881
882static UnaryTypeTrait UnaryTypeTraitFromTokKind(tok::TokenKind kind)
883{
884  switch(kind) {
885  default: assert(false && "Not a known unary type trait.");
886  case tok::kw___has_nothrow_assign:      return UTT_HasNothrowAssign;
887  case tok::kw___has_nothrow_copy:        return UTT_HasNothrowCopy;
888  case tok::kw___has_nothrow_constructor: return UTT_HasNothrowConstructor;
889  case tok::kw___has_trivial_assign:      return UTT_HasTrivialAssign;
890  case tok::kw___has_trivial_copy:        return UTT_HasTrivialCopy;
891  case tok::kw___has_trivial_constructor: return UTT_HasTrivialConstructor;
892  case tok::kw___has_trivial_destructor:  return UTT_HasTrivialDestructor;
893  case tok::kw___has_virtual_destructor:  return UTT_HasVirtualDestructor;
894  case tok::kw___is_abstract:             return UTT_IsAbstract;
895  case tok::kw___is_class:                return UTT_IsClass;
896  case tok::kw___is_empty:                return UTT_IsEmpty;
897  case tok::kw___is_enum:                 return UTT_IsEnum;
898  case tok::kw___is_pod:                  return UTT_IsPOD;
899  case tok::kw___is_polymorphic:          return UTT_IsPolymorphic;
900  case tok::kw___is_union:                return UTT_IsUnion;
901  }
902}
903
904/// ParseUnaryTypeTrait - Parse the built-in unary type-trait
905/// pseudo-functions that allow implementation of the TR1/C++0x type traits
906/// templates.
907///
908///       primary-expression:
909/// [GNU]             unary-type-trait '(' type-id ')'
910///
911Parser::OwningExprResult Parser::ParseUnaryTypeTrait()
912{
913  UnaryTypeTrait UTT = UnaryTypeTraitFromTokKind(Tok.getKind());
914  SourceLocation Loc = ConsumeToken();
915
916  SourceLocation LParen = Tok.getLocation();
917  if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen))
918    return ExprError();
919
920  // FIXME: Error reporting absolutely sucks! If the this fails to parse a type
921  // there will be cryptic errors about mismatched parentheses and missing
922  // specifiers.
923  TypeResult Ty = ParseTypeName();
924
925  SourceLocation RParen = MatchRHSPunctuation(tok::r_paren, LParen);
926
927  if (Ty.isInvalid())
928    return ExprError();
929
930  return Actions.ActOnUnaryTypeTrait(UTT, Loc, LParen, Ty.get(), RParen);
931}
932