blob: 195b52e9885c14a3eeb96b72fa0f166d3d135eb2 [file] [log] [blame]
Chris Lattner4b009652007-07-25 00:24:17 +00001//===--- ParseExprCXX.cpp - C++ Expression Parsing ------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
Chris Lattner959e5be2007-12-29 19:59:25 +00005// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
Chris Lattner4b009652007-07-25 00:24:17 +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"
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +000016#include "clang/Parse/DeclSpec.h"
Sebastian Redl6008ac32008-11-25 22:21:31 +000017#include "AstGuard.h"
Chris Lattner4b009652007-07-25 00:24:17 +000018using namespace clang;
19
Argiris Kirtzidis91c80dc2008-11-26 21:41:52 +000020/// MaybeParseCXXScopeSpecifier - Parse global scope or nested-name-specifier.
21/// Returns true if a nested-name-specifier was parsed from the token stream.
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000022///
23/// '::'[opt] nested-name-specifier
24/// '::'
25///
26/// nested-name-specifier:
27/// type-name '::'
28/// namespace-name '::'
29/// nested-name-specifier identifier '::'
30/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
31///
Chris Lattner1e015942009-01-04 23:23:14 +000032bool Parser::MaybeParseCXXScopeSpecifier(CXXScopeSpec &SS,
33 const Token *GlobalQualifier) {
Argiris Kirtzidis91c80dc2008-11-26 21:41:52 +000034 assert(getLang().CPlusPlus &&
35 "Call sites of this function should be guarded by checking for C++.");
36
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000037 if (Tok.is(tok::annot_cxxscope)) {
Chris Lattner1e015942009-01-04 23:23:14 +000038 assert(GlobalQualifier == 0 &&
39 "Cannot have :: followed by a resolve annotation scope");
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000040 SS.setScopeRep(Tok.getAnnotationValue());
41 SS.setRange(Tok.getAnnotationRange());
42 ConsumeToken();
Argiris Kirtzidis91c80dc2008-11-26 21:41:52 +000043 return true;
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000044 }
Chris Lattner99113932009-01-04 21:14:15 +000045
Chris Lattner1e015942009-01-04 23:23:14 +000046 if (GlobalQualifier == 0 &&
47 Tok.isNot(tok::coloncolon) &&
Chris Lattner99113932009-01-04 21:14:15 +000048 (Tok.isNot(tok::identifier) || NextToken().isNot(tok::coloncolon)))
49 return false;
50
51 // ::new and ::delete aren't nested-name-specifiers, so parsing the :: as
52 // a scope specifier only makes things more complicated.
Chris Lattner1e015942009-01-04 23:23:14 +000053 if (GlobalQualifier == 0 && Tok.is(tok::coloncolon)) {
Chris Lattner99113932009-01-04 21:14:15 +000054 Token Next = NextToken();
55 if (Next.is(tok::kw_new) || Next.is(tok::kw_delete))
56 return false;
57 }
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000058
Chris Lattner1e015942009-01-04 23:23:14 +000059 if (GlobalQualifier) {
60 // Pre-parsed '::'.
61 SS.setBeginLoc(GlobalQualifier->getLocation());
62 SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope,
63 GlobalQualifier->getLocation()));
64 SS.setEndLoc(GlobalQualifier->getLocation());
65 } else {
66 SS.setBeginLoc(Tok.getLocation());
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000067
Chris Lattner1e015942009-01-04 23:23:14 +000068 // '::'
69 if (Tok.is(tok::coloncolon)) {
70 // Global scope.
71 SourceLocation CCLoc = ConsumeToken();
72 SS.setScopeRep(Actions.ActOnCXXGlobalScopeSpecifier(CurScope, CCLoc));
73 SS.setEndLoc(CCLoc);
74 }
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000075 }
76
77 // nested-name-specifier:
78 // type-name '::'
79 // namespace-name '::'
80 // nested-name-specifier identifier '::'
81 // nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000082 while (Tok.is(tok::identifier) && NextToken().is(tok::coloncolon)) {
83 IdentifierInfo *II = Tok.getIdentifierInfo();
84 SourceLocation IdLoc = ConsumeToken();
Chris Lattner99113932009-01-04 21:14:15 +000085 assert(Tok.is(tok::coloncolon) && "NextToken() not working properly!");
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000086 SourceLocation CCLoc = ConsumeToken();
87 if (SS.isInvalid())
88 continue;
89
90 SS.setScopeRep(
Chris Lattner99113932009-01-04 21:14:15 +000091 Actions.ActOnCXXNestedNameSpecifier(CurScope, SS, IdLoc, CCLoc, *II));
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000092 SS.setEndLoc(CCLoc);
93 }
Argiris Kirtzidis91c80dc2008-11-26 21:41:52 +000094
95 return true;
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +000096}
97
98/// ParseCXXIdExpression - Handle id-expression.
99///
100/// id-expression:
101/// unqualified-id
102/// qualified-id
103///
104/// unqualified-id:
105/// identifier
106/// operator-function-id
107/// conversion-function-id [TODO]
108/// '~' class-name [TODO]
109/// template-id [TODO]
110///
111/// qualified-id:
112/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
113/// '::' identifier
114/// '::' operator-function-id
115/// '::' template-id [TODO]
116///
117/// nested-name-specifier:
118/// type-name '::'
119/// namespace-name '::'
120/// nested-name-specifier identifier '::'
121/// nested-name-specifier 'template'[opt] simple-template-id '::' [TODO]
122///
123/// NOTE: The standard specifies that, for qualified-id, the parser does not
124/// expect:
125///
126/// '::' conversion-function-id
127/// '::' '~' class-name
128///
129/// This may cause a slight inconsistency on diagnostics:
130///
131/// class C {};
132/// namespace A {}
133/// void f() {
134/// :: A :: ~ C(); // Some Sema error about using destructor with a
135/// // namespace.
136/// :: ~ C(); // Some Parser error like 'unexpected ~'.
137/// }
138///
139/// We simplify the parser a bit and make it work like:
140///
141/// qualified-id:
142/// '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
143/// '::' unqualified-id
144///
145/// That way Sema can handle and report similar errors for namespaces and the
146/// global scope.
147///
Sebastian Redl39d4f022008-12-11 22:51:44 +0000148Parser::OwningExprResult Parser::ParseCXXIdExpression() {
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000149 // qualified-id:
150 // '::'[opt] nested-name-specifier 'template'[opt] unqualified-id
151 // '::' unqualified-id
152 //
153 CXXScopeSpec SS;
Argiris Kirtzidis91c80dc2008-11-26 21:41:52 +0000154 MaybeParseCXXScopeSpecifier(SS);
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000155
156 // unqualified-id:
157 // identifier
158 // operator-function-id
Douglas Gregorb0212bd2008-11-17 20:34:05 +0000159 // conversion-function-id
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000160 // '~' class-name [TODO]
161 // template-id [TODO]
162 //
163 switch (Tok.getKind()) {
164 default:
Sebastian Redl39d4f022008-12-11 22:51:44 +0000165 return ExprError(Diag(Tok, diag::err_expected_unqualified_id));
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000166
167 case tok::identifier: {
168 // Consume the identifier so that we can see if it is followed by a '('.
169 IdentifierInfo &II = *Tok.getIdentifierInfo();
170 SourceLocation L = ConsumeToken();
Sebastian Redl39d4f022008-12-11 22:51:44 +0000171 return Owned(Actions.ActOnIdentifierExpr(CurScope, L, II,
172 Tok.is(tok::l_paren), &SS));
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000173 }
174
175 case tok::kw_operator: {
176 SourceLocation OperatorLoc = Tok.getLocation();
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000177 if (OverloadedOperatorKind Op = TryParseOperatorFunctionId()) {
Sebastian Redl39d4f022008-12-11 22:51:44 +0000178 return Owned(Actions.ActOnCXXOperatorFunctionIdExpr(
179 CurScope, OperatorLoc, Op, Tok.is(tok::l_paren), SS));
Douglas Gregorb0212bd2008-11-17 20:34:05 +0000180 } else if (TypeTy *Type = ParseConversionFunctionId()) {
Sebastian Redl39d4f022008-12-11 22:51:44 +0000181 return Owned(Actions.ActOnCXXConversionFunctionExpr(
182 CurScope, OperatorLoc, Type, Tok.is(tok::l_paren),SS));
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000183 }
Sebastian Redl39d4f022008-12-11 22:51:44 +0000184
Douglas Gregorb0212bd2008-11-17 20:34:05 +0000185 // We already complained about a bad conversion-function-id,
186 // above.
Sebastian Redl39d4f022008-12-11 22:51:44 +0000187 return ExprError();
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000188 }
189
190 } // switch.
191
192 assert(0 && "The switch was supposed to take care everything.");
193}
194
Chris Lattner4b009652007-07-25 00:24:17 +0000195/// ParseCXXCasts - This handles the various ways to cast expressions to another
196/// type.
197///
198/// postfix-expression: [C++ 5.2p1]
199/// 'dynamic_cast' '<' type-name '>' '(' expression ')'
200/// 'static_cast' '<' type-name '>' '(' expression ')'
201/// 'reinterpret_cast' '<' type-name '>' '(' expression ')'
202/// 'const_cast' '<' type-name '>' '(' expression ')'
203///
Sebastian Redl39d4f022008-12-11 22:51:44 +0000204Parser::OwningExprResult Parser::ParseCXXCasts() {
Chris Lattner4b009652007-07-25 00:24:17 +0000205 tok::TokenKind Kind = Tok.getKind();
206 const char *CastName = 0; // For error messages
207
208 switch (Kind) {
209 default: assert(0 && "Unknown C++ cast!"); abort();
210 case tok::kw_const_cast: CastName = "const_cast"; break;
211 case tok::kw_dynamic_cast: CastName = "dynamic_cast"; break;
212 case tok::kw_reinterpret_cast: CastName = "reinterpret_cast"; break;
213 case tok::kw_static_cast: CastName = "static_cast"; break;
214 }
215
216 SourceLocation OpLoc = ConsumeToken();
217 SourceLocation LAngleBracketLoc = Tok.getLocation();
218
219 if (ExpectAndConsume(tok::less, diag::err_expected_less_after, CastName))
Sebastian Redl39d4f022008-12-11 22:51:44 +0000220 return ExprError();
Chris Lattner4b009652007-07-25 00:24:17 +0000221
222 TypeTy *CastTy = ParseTypeName();
223 SourceLocation RAngleBracketLoc = Tok.getLocation();
224
Chris Lattnerf006a222008-11-18 07:48:38 +0000225 if (ExpectAndConsume(tok::greater, diag::err_expected_greater))
Sebastian Redl39d4f022008-12-11 22:51:44 +0000226 return ExprError(Diag(LAngleBracketLoc, diag::note_matching) << "<");
Chris Lattner4b009652007-07-25 00:24:17 +0000227
228 SourceLocation LParenLoc = Tok.getLocation(), RParenLoc;
229
Chris Lattnerf006a222008-11-18 07:48:38 +0000230 if (Tok.isNot(tok::l_paren))
Sebastian Redl39d4f022008-12-11 22:51:44 +0000231 return ExprError(Diag(Tok, diag::err_expected_lparen_after) << CastName);
Chris Lattner4b009652007-07-25 00:24:17 +0000232
Sebastian Redla6817a02008-12-11 22:33:27 +0000233 OwningExprResult Result(ParseSimpleParenExpression(RParenLoc));
Chris Lattner4b009652007-07-25 00:24:17 +0000234
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000235 if (!Result.isInvalid())
Douglas Gregor21a04f32008-10-27 19:41:14 +0000236 Result = Actions.ActOnCXXNamedCast(OpLoc, Kind,
237 LAngleBracketLoc, CastTy, RAngleBracketLoc,
Sebastian Redl6f1ee232008-12-10 00:02:53 +0000238 LParenLoc, Result.release(), RParenLoc);
Chris Lattner4b009652007-07-25 00:24:17 +0000239
Sebastian Redl39d4f022008-12-11 22:51:44 +0000240 return move(Result);
Chris Lattner4b009652007-07-25 00:24:17 +0000241}
242
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000243/// ParseCXXTypeid - This handles the C++ typeid expression.
244///
245/// postfix-expression: [C++ 5.2p1]
246/// 'typeid' '(' expression ')'
247/// 'typeid' '(' type-id ')'
248///
Sebastian Redl39d4f022008-12-11 22:51:44 +0000249Parser::OwningExprResult Parser::ParseCXXTypeid() {
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000250 assert(Tok.is(tok::kw_typeid) && "Not 'typeid'!");
251
252 SourceLocation OpLoc = ConsumeToken();
253 SourceLocation LParenLoc = Tok.getLocation();
254 SourceLocation RParenLoc;
255
256 // typeid expressions are always parenthesized.
257 if (ExpectAndConsume(tok::l_paren, diag::err_expected_lparen_after,
258 "typeid"))
Sebastian Redl39d4f022008-12-11 22:51:44 +0000259 return ExprError();
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000260
Sebastian Redl62261042008-12-09 20:22:58 +0000261 OwningExprResult Result(Actions);
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000262
263 if (isTypeIdInParens()) {
264 TypeTy *Ty = ParseTypeName();
265
266 // Match the ')'.
267 MatchRHSPunctuation(tok::r_paren, LParenLoc);
268
269 if (!Ty)
Sebastian Redl39d4f022008-12-11 22:51:44 +0000270 return ExprError();
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000271
272 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/true,
273 Ty, RParenLoc);
274 } else {
275 Result = ParseExpression();
276
277 // Match the ')'.
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000278 if (Result.isInvalid())
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000279 SkipUntil(tok::r_paren);
280 else {
281 MatchRHSPunctuation(tok::r_paren, LParenLoc);
282
283 Result = Actions.ActOnCXXTypeid(OpLoc, LParenLoc, /*isType=*/false,
Sebastian Redl6f1ee232008-12-10 00:02:53 +0000284 Result.release(), RParenLoc);
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000285 }
286 }
287
Sebastian Redl39d4f022008-12-11 22:51:44 +0000288 return move(Result);
Sebastian Redlb93b49c2008-11-11 11:37:55 +0000289}
290
Chris Lattner4b009652007-07-25 00:24:17 +0000291/// ParseCXXBoolLiteral - This handles the C++ Boolean literals.
292///
293/// boolean-literal: [C++ 2.13.5]
294/// 'true'
295/// 'false'
Sebastian Redl39d4f022008-12-11 22:51:44 +0000296Parser::OwningExprResult Parser::ParseCXXBoolLiteral() {
Chris Lattner4b009652007-07-25 00:24:17 +0000297 tok::TokenKind Kind = Tok.getKind();
Sebastian Redl39d4f022008-12-11 22:51:44 +0000298 return Owned(Actions.ActOnCXXBoolLiteral(ConsumeToken(), Kind));
Chris Lattner4b009652007-07-25 00:24:17 +0000299}
Chris Lattnera7447ba2008-02-26 00:51:44 +0000300
301/// ParseThrowExpression - This handles the C++ throw expression.
302///
303/// throw-expression: [C++ 15]
304/// 'throw' assignment-expression[opt]
Sebastian Redl39d4f022008-12-11 22:51:44 +0000305Parser::OwningExprResult Parser::ParseThrowExpression() {
Chris Lattnera7447ba2008-02-26 00:51:44 +0000306 assert(Tok.is(tok::kw_throw) && "Not throw!");
Chris Lattnera7447ba2008-02-26 00:51:44 +0000307 SourceLocation ThrowLoc = ConsumeToken(); // Eat the throw token.
Sebastian Redl39d4f022008-12-11 22:51:44 +0000308
Chris Lattner6b8842d2008-04-06 06:02:23 +0000309 // If the current token isn't the start of an assignment-expression,
310 // then the expression is not present. This handles things like:
311 // "C ? throw : (void)42", which is crazy but legal.
312 switch (Tok.getKind()) { // FIXME: move this predicate somewhere common.
313 case tok::semi:
314 case tok::r_paren:
315 case tok::r_square:
316 case tok::r_brace:
317 case tok::colon:
318 case tok::comma:
Sebastian Redl39d4f022008-12-11 22:51:44 +0000319 return Owned(Actions.ActOnCXXThrow(ThrowLoc));
Chris Lattnera7447ba2008-02-26 00:51:44 +0000320
Chris Lattner6b8842d2008-04-06 06:02:23 +0000321 default:
Sebastian Redl14ca7412008-12-11 21:36:32 +0000322 OwningExprResult Expr(ParseAssignmentExpression());
Sebastian Redl39d4f022008-12-11 22:51:44 +0000323 if (Expr.isInvalid()) return move(Expr);
324 return Owned(Actions.ActOnCXXThrow(ThrowLoc, Expr.release()));
Chris Lattner6b8842d2008-04-06 06:02:23 +0000325 }
Chris Lattnera7447ba2008-02-26 00:51:44 +0000326}
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000327
328/// ParseCXXThis - This handles the C++ 'this' pointer.
329///
330/// C++ 9.3.2: In the body of a non-static member function, the keyword this is
331/// a non-lvalue expression whose value is the address of the object for which
332/// the function is called.
Sebastian Redl39d4f022008-12-11 22:51:44 +0000333Parser::OwningExprResult Parser::ParseCXXThis() {
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000334 assert(Tok.is(tok::kw_this) && "Not 'this'!");
335 SourceLocation ThisLoc = ConsumeToken();
Sebastian Redl39d4f022008-12-11 22:51:44 +0000336 return Owned(Actions.ActOnCXXThis(ThisLoc));
Argiris Kirtzidis9d784332008-06-24 22:12:16 +0000337}
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000338
339/// ParseCXXTypeConstructExpression - Parse construction of a specified type.
340/// Can be interpreted either as function-style casting ("int(x)")
341/// or class type construction ("ClassType(x,y,z)")
342/// or creation of a value-initialized type ("int()").
343///
344/// postfix-expression: [C++ 5.2p1]
345/// simple-type-specifier '(' expression-list[opt] ')' [C++ 5.2.3]
346/// typename-specifier '(' expression-list[opt] ')' [TODO]
347///
Sebastian Redl39d4f022008-12-11 22:51:44 +0000348Parser::OwningExprResult
349Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) {
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000350 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
351 TypeTy *TypeRep = Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
352
353 assert(Tok.is(tok::l_paren) && "Expected '('!");
354 SourceLocation LParenLoc = ConsumeParen();
355
Sebastian Redl6008ac32008-11-25 22:21:31 +0000356 ExprVector Exprs(Actions);
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000357 CommaLocsTy CommaLocs;
358
359 if (Tok.isNot(tok::r_paren)) {
360 if (ParseExpressionList(Exprs, CommaLocs)) {
361 SkipUntil(tok::r_paren);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000362 return ExprError();
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000363 }
364 }
365
366 // Match the ')'.
367 SourceLocation RParenLoc = MatchRHSPunctuation(tok::r_paren, LParenLoc);
368
369 assert((Exprs.size() == 0 || Exprs.size()-1 == CommaLocs.size())&&
370 "Unexpected number of commas!");
Sebastian Redl39d4f022008-12-11 22:51:44 +0000371 return Owned(Actions.ActOnCXXTypeConstructExpr(DS.getSourceRange(), TypeRep,
372 LParenLoc,
373 Exprs.take(), Exprs.size(),
374 &CommaLocs[0], RParenLoc));
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000375}
376
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000377/// ParseCXXCondition - if/switch/while/for condition expression.
378///
379/// condition:
380/// expression
381/// type-specifier-seq declarator '=' assignment-expression
382/// [GNU] type-specifier-seq declarator simple-asm-expr[opt] attributes[opt]
383/// '=' assignment-expression
384///
Sebastian Redl14ca7412008-12-11 21:36:32 +0000385Parser::OwningExprResult Parser::ParseCXXCondition() {
Argiris Kirtzidis88527fb2008-10-05 15:03:47 +0000386 if (!isCXXConditionDeclaration())
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000387 return ParseExpression(); // expression
388
389 SourceLocation StartLoc = Tok.getLocation();
390
391 // type-specifier-seq
392 DeclSpec DS;
393 ParseSpecifierQualifierList(DS);
394
395 // declarator
396 Declarator DeclaratorInfo(DS, Declarator::ConditionContext);
397 ParseDeclarator(DeclaratorInfo);
398
399 // simple-asm-expr[opt]
400 if (Tok.is(tok::kw_asm)) {
Sebastian Redl6f1ee232008-12-10 00:02:53 +0000401 OwningExprResult AsmLabel(ParseSimpleAsm());
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000402 if (AsmLabel.isInvalid()) {
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000403 SkipUntil(tok::semi);
Sebastian Redl14ca7412008-12-11 21:36:32 +0000404 return ExprError();
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000405 }
Sebastian Redl6f1ee232008-12-10 00:02:53 +0000406 DeclaratorInfo.setAsmLabel(AsmLabel.release());
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000407 }
408
409 // If attributes are present, parse them.
410 if (Tok.is(tok::kw___attribute))
411 DeclaratorInfo.AddAttributes(ParseAttributes());
412
413 // '=' assignment-expression
414 if (Tok.isNot(tok::equal))
Sebastian Redl14ca7412008-12-11 21:36:32 +0000415 return ExprError(Diag(Tok, diag::err_expected_equal_after_declarator));
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000416 SourceLocation EqualLoc = ConsumeToken();
Sebastian Redl14ca7412008-12-11 21:36:32 +0000417 OwningExprResult AssignExpr(ParseAssignmentExpression());
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000418 if (AssignExpr.isInvalid())
Sebastian Redl14ca7412008-12-11 21:36:32 +0000419 return ExprError();
420
421 return Owned(Actions.ActOnCXXConditionDeclarationExpr(CurScope, StartLoc,
422 DeclaratorInfo,EqualLoc,
423 AssignExpr.release()));
Argiris Kirtzidis873f2782008-09-09 20:38:47 +0000424}
425
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000426/// ParseCXXSimpleTypeSpecifier - [C++ 7.1.5.2] Simple type specifiers.
427/// This should only be called when the current token is known to be part of
428/// simple-type-specifier.
429///
430/// simple-type-specifier:
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000431/// '::'[opt] nested-name-specifier[opt] type-name
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000432/// '::'[opt] nested-name-specifier 'template' simple-template-id [TODO]
433/// char
434/// wchar_t
435/// bool
436/// short
437/// int
438/// long
439/// signed
440/// unsigned
441/// float
442/// double
443/// void
444/// [GNU] typeof-specifier
445/// [C++0x] auto [TODO]
446///
447/// type-name:
448/// class-name
449/// enum-name
450/// typedef-name
451///
452void Parser::ParseCXXSimpleTypeSpecifier(DeclSpec &DS) {
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000453 // Annotate typenames and C++ scope specifiers.
454 TryAnnotateTypeOrScopeToken();
455
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000456 DS.SetRangeStart(Tok.getLocation());
457 const char *PrevSpec;
458 SourceLocation Loc = Tok.getLocation();
459
460 switch (Tok.getKind()) {
461 default:
462 assert(0 && "Not a simple-type-specifier token!");
463 abort();
464
465 // type-name
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000466 case tok::annot_qualtypename: {
467 DS.SetTypeSpecType(DeclSpec::TST_typedef, Loc, PrevSpec,
468 Tok.getAnnotationValue());
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000469 break;
470 }
471
472 // builtin types
473 case tok::kw_short:
474 DS.SetTypeSpecWidth(DeclSpec::TSW_short, Loc, PrevSpec);
475 break;
476 case tok::kw_long:
477 DS.SetTypeSpecWidth(DeclSpec::TSW_long, Loc, PrevSpec);
478 break;
479 case tok::kw_signed:
480 DS.SetTypeSpecSign(DeclSpec::TSS_signed, Loc, PrevSpec);
481 break;
482 case tok::kw_unsigned:
483 DS.SetTypeSpecSign(DeclSpec::TSS_unsigned, Loc, PrevSpec);
484 break;
485 case tok::kw_void:
486 DS.SetTypeSpecType(DeclSpec::TST_void, Loc, PrevSpec);
487 break;
488 case tok::kw_char:
489 DS.SetTypeSpecType(DeclSpec::TST_char, Loc, PrevSpec);
490 break;
491 case tok::kw_int:
492 DS.SetTypeSpecType(DeclSpec::TST_int, Loc, PrevSpec);
493 break;
494 case tok::kw_float:
495 DS.SetTypeSpecType(DeclSpec::TST_float, Loc, PrevSpec);
496 break;
497 case tok::kw_double:
498 DS.SetTypeSpecType(DeclSpec::TST_double, Loc, PrevSpec);
499 break;
500 case tok::kw_wchar_t:
501 DS.SetTypeSpecType(DeclSpec::TST_wchar, Loc, PrevSpec);
502 break;
503 case tok::kw_bool:
504 DS.SetTypeSpecType(DeclSpec::TST_bool, Loc, PrevSpec);
505 break;
506
507 // GNU typeof support.
508 case tok::kw_typeof:
509 ParseTypeofSpecifier(DS);
510 DS.Finish(Diags, PP.getSourceManager(), getLang());
511 return;
512 }
Argiris Kirtzidis311db8c2008-11-08 16:45:02 +0000513 if (Tok.is(tok::annot_qualtypename))
514 DS.SetRangeEnd(Tok.getAnnotationEndLoc());
515 else
516 DS.SetRangeEnd(Tok.getLocation());
Argiris Kirtzidis7a1e7412008-08-22 15:38:55 +0000517 ConsumeToken();
518 DS.Finish(Diags, PP.getSourceManager(), getLang());
519}
Douglas Gregore60e5d32008-11-06 22:13:31 +0000520
Douglas Gregor3ef6c972008-11-07 20:08:42 +0000521/// ParseCXXTypeSpecifierSeq - Parse a C++ type-specifier-seq (C++
522/// [dcl.name]), which is a non-empty sequence of type-specifiers,
523/// e.g., "const short int". Note that the DeclSpec is *not* finished
524/// by parsing the type-specifier-seq, because these sequences are
525/// typically followed by some form of declarator. Returns true and
526/// emits diagnostics if this is not a type-specifier-seq, false
527/// otherwise.
528///
529/// type-specifier-seq: [C++ 8.1]
530/// type-specifier type-specifier-seq[opt]
531///
532bool Parser::ParseCXXTypeSpecifierSeq(DeclSpec &DS) {
533 DS.SetRangeStart(Tok.getLocation());
534 const char *PrevSpec = 0;
535 int isInvalid = 0;
536
537 // Parse one or more of the type specifiers.
538 if (!MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) {
Chris Lattnerf006a222008-11-18 07:48:38 +0000539 Diag(Tok, diag::err_operator_missing_type_specifier);
Douglas Gregor3ef6c972008-11-07 20:08:42 +0000540 return true;
541 }
Daniel Dunbar19fa6fb2008-11-08 04:28:37 +0000542 while (MaybeParseTypeSpecifier(DS, isInvalid, PrevSpec)) ;
Douglas Gregor3ef6c972008-11-07 20:08:42 +0000543
544 return false;
545}
546
Douglas Gregor682a8cf2008-11-17 16:14:12 +0000547/// TryParseOperatorFunctionId - Attempts to parse a C++ overloaded
Douglas Gregore60e5d32008-11-06 22:13:31 +0000548/// operator name (C++ [over.oper]). If successful, returns the
549/// predefined identifier that corresponds to that overloaded
550/// operator. Otherwise, returns NULL and does not consume any tokens.
551///
552/// operator-function-id: [C++ 13.5]
553/// 'operator' operator
554///
555/// operator: one of
556/// new delete new[] delete[]
557/// + - * / % ^ & | ~
558/// ! = < > += -= *= /= %=
559/// ^= &= |= << >> >>= <<= == !=
560/// <= >= && || ++ -- , ->* ->
561/// () []
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000562OverloadedOperatorKind Parser::TryParseOperatorFunctionId() {
Argiris Kirtzidisa9d57b62008-11-07 15:54:02 +0000563 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
Douglas Gregore60e5d32008-11-06 22:13:31 +0000564
565 OverloadedOperatorKind Op = OO_None;
566 switch (NextToken().getKind()) {
567 case tok::kw_new:
568 ConsumeToken(); // 'operator'
569 ConsumeToken(); // 'new'
570 if (Tok.is(tok::l_square)) {
571 ConsumeBracket(); // '['
572 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
573 Op = OO_Array_New;
574 } else {
575 Op = OO_New;
576 }
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000577 return Op;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000578
579 case tok::kw_delete:
580 ConsumeToken(); // 'operator'
581 ConsumeToken(); // 'delete'
582 if (Tok.is(tok::l_square)) {
583 ConsumeBracket(); // '['
584 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
585 Op = OO_Array_Delete;
586 } else {
587 Op = OO_Delete;
588 }
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000589 return Op;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000590
Douglas Gregor9c6210b2008-11-10 13:38:07 +0000591#define OVERLOADED_OPERATOR(Name,Spelling,Token,Unary,Binary,MemberOnly) \
Douglas Gregore60e5d32008-11-06 22:13:31 +0000592 case tok::Token: Op = OO_##Name; break;
Douglas Gregor9c6210b2008-11-10 13:38:07 +0000593#define OVERLOADED_OPERATOR_MULTI(Name,Spelling,Unary,Binary,MemberOnly)
Douglas Gregore60e5d32008-11-06 22:13:31 +0000594#include "clang/Basic/OperatorKinds.def"
595
596 case tok::l_paren:
597 ConsumeToken(); // 'operator'
598 ConsumeParen(); // '('
599 ExpectAndConsume(tok::r_paren, diag::err_expected_rparen); // ')'
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000600 return OO_Call;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000601
602 case tok::l_square:
603 ConsumeToken(); // 'operator'
604 ConsumeBracket(); // '['
605 ExpectAndConsume(tok::r_square, diag::err_expected_rsquare); // ']'
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000606 return OO_Subscript;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000607
608 default:
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000609 return OO_None;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000610 }
611
Douglas Gregor682a8cf2008-11-17 16:14:12 +0000612 ConsumeToken(); // 'operator'
613 ConsumeAnyToken(); // the operator itself
Douglas Gregor96a32dd2008-11-18 14:39:36 +0000614 return Op;
Douglas Gregore60e5d32008-11-06 22:13:31 +0000615}
Douglas Gregor3ef6c972008-11-07 20:08:42 +0000616
617/// ParseConversionFunctionId - Parse a C++ conversion-function-id,
618/// which expresses the name of a user-defined conversion operator
619/// (C++ [class.conv.fct]p1). Returns the type that this operator is
620/// specifying a conversion for, or NULL if there was an error.
621///
622/// conversion-function-id: [C++ 12.3.2]
623/// operator conversion-type-id
624///
625/// conversion-type-id:
626/// type-specifier-seq conversion-declarator[opt]
627///
628/// conversion-declarator:
629/// ptr-operator conversion-declarator[opt]
630Parser::TypeTy *Parser::ParseConversionFunctionId() {
631 assert(Tok.is(tok::kw_operator) && "Expected 'operator' keyword");
632 ConsumeToken(); // 'operator'
633
634 // Parse the type-specifier-seq.
635 DeclSpec DS;
636 if (ParseCXXTypeSpecifierSeq(DS))
637 return 0;
638
639 // Parse the conversion-declarator, which is merely a sequence of
640 // ptr-operators.
641 Declarator D(DS, Declarator::TypeNameContext);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000642 ParseDeclaratorInternal(D, /*DirectDeclParser=*/0);
Douglas Gregor3ef6c972008-11-07 20:08:42 +0000643
644 // Finish up the type.
645 Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D);
646 if (Result.isInvalid)
647 return 0;
648 else
649 return Result.Val;
650}
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000651
652/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate
653/// memory in a typesafe manner and call constructors.
Chris Lattnere7de3612009-01-04 21:25:24 +0000654///
655/// This method is called to parse the new expression after the optional :: has
656/// been already parsed. If the :: was present, "UseGlobal" is true and "Start"
657/// is its location. Otherwise, "Start" is the location of the 'new' token.
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000658///
659/// new-expression:
660/// '::'[opt] 'new' new-placement[opt] new-type-id
661/// new-initializer[opt]
662/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
663/// new-initializer[opt]
664///
665/// new-placement:
666/// '(' expression-list ')'
667///
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000668/// new-type-id:
669/// type-specifier-seq new-declarator[opt]
670///
671/// new-declarator:
672/// ptr-operator new-declarator[opt]
673/// direct-new-declarator
674///
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000675/// new-initializer:
676/// '(' expression-list[opt] ')'
677/// [C++0x] braced-init-list [TODO]
678///
Chris Lattnere7de3612009-01-04 21:25:24 +0000679Parser::OwningExprResult
680Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
681 assert(Tok.is(tok::kw_new) && "expected 'new' token");
682 ConsumeToken(); // Consume 'new'
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000683
684 // A '(' now can be a new-placement or the '(' wrapping the type-id in the
685 // second form of new-expression. It can't be a new-type-id.
686
Sebastian Redl6008ac32008-11-25 22:21:31 +0000687 ExprVector PlacementArgs(Actions);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000688 SourceLocation PlacementLParen, PlacementRParen;
689
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000690 bool ParenTypeId;
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000691 DeclSpec DS;
692 Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000693 if (Tok.is(tok::l_paren)) {
694 // If it turns out to be a placement, we change the type location.
695 PlacementLParen = ConsumeParen();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000696 if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
697 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000698 return ExprError();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000699 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000700
701 PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000702 if (PlacementRParen.isInvalid()) {
703 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000704 return ExprError();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000705 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000706
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000707 if (PlacementArgs.empty()) {
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000708 // Reset the placement locations. There was no placement.
709 PlacementLParen = PlacementRParen = SourceLocation();
710 ParenTypeId = true;
711 } else {
712 // We still need the type.
713 if (Tok.is(tok::l_paren)) {
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000714 SourceLocation LParen = ConsumeParen();
715 ParseSpecifierQualifierList(DS);
716 ParseDeclarator(DeclaratorInfo);
717 MatchRHSPunctuation(tok::r_paren, LParen);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000718 ParenTypeId = true;
719 } else {
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000720 if (ParseCXXTypeSpecifierSeq(DS))
721 DeclaratorInfo.setInvalidType(true);
722 else
723 ParseDeclaratorInternal(DeclaratorInfo,
724 &Parser::ParseDirectNewDeclarator);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000725 ParenTypeId = false;
726 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000727 }
728 } else {
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000729 // A new-type-id is a simplified type-id, where essentially the
730 // direct-declarator is replaced by a direct-new-declarator.
731 if (ParseCXXTypeSpecifierSeq(DS))
732 DeclaratorInfo.setInvalidType(true);
733 else
734 ParseDeclaratorInternal(DeclaratorInfo,
735 &Parser::ParseDirectNewDeclarator);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000736 ParenTypeId = false;
737 }
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000738 if (DeclaratorInfo.getInvalidType()) {
739 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000740 return ExprError();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000741 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000742
Sebastian Redl6008ac32008-11-25 22:21:31 +0000743 ExprVector ConstructorArgs(Actions);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000744 SourceLocation ConstructorLParen, ConstructorRParen;
745
746 if (Tok.is(tok::l_paren)) {
747 ConstructorLParen = ConsumeParen();
748 if (Tok.isNot(tok::r_paren)) {
749 CommaLocsTy CommaLocs;
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000750 if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
751 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000752 return ExprError();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000753 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000754 }
755 ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000756 if (ConstructorRParen.isInvalid()) {
757 SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
Sebastian Redl39d4f022008-12-11 22:51:44 +0000758 return ExprError();
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000759 }
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000760 }
761
Sebastian Redl39d4f022008-12-11 22:51:44 +0000762 return Owned(Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
763 PlacementArgs.take(), PlacementArgs.size(),
764 PlacementRParen, ParenTypeId, DeclaratorInfo,
765 ConstructorLParen, ConstructorArgs.take(),
766 ConstructorArgs.size(), ConstructorRParen));
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000767}
768
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000769/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be
770/// passed to ParseDeclaratorInternal.
771///
772/// direct-new-declarator:
773/// '[' expression ']'
774/// direct-new-declarator '[' constant-expression ']'
775///
Chris Lattnere7de3612009-01-04 21:25:24 +0000776void Parser::ParseDirectNewDeclarator(Declarator &D) {
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000777 // Parse the array dimensions.
778 bool first = true;
779 while (Tok.is(tok::l_square)) {
780 SourceLocation LLoc = ConsumeBracket();
Sebastian Redl14ca7412008-12-11 21:36:32 +0000781 OwningExprResult Size(first ? ParseExpression()
782 : ParseConstantExpression());
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000783 if (Size.isInvalid()) {
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000784 // Recover
785 SkipUntil(tok::r_square);
786 return;
787 }
788 first = false;
789
790 D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false,
Sebastian Redl6f1ee232008-12-10 00:02:53 +0000791 Size.release(), LLoc));
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000792
793 if (MatchRHSPunctuation(tok::r_square, LLoc).isInvalid())
794 return;
795 }
796}
797
798/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id.
799/// This ambiguity appears in the syntax of the C++ new operator.
800///
801/// new-expression:
802/// '::'[opt] 'new' new-placement[opt] '(' type-id ')'
803/// new-initializer[opt]
804///
805/// new-placement:
806/// '(' expression-list ')'
807///
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000808bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
Chris Lattnere7de3612009-01-04 21:25:24 +0000809 Declarator &D) {
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000810 // The '(' was already consumed.
811 if (isTypeIdInParens()) {
Sebastian Redl66df3ef2008-12-02 14:43:59 +0000812 ParseSpecifierQualifierList(D.getMutableDeclSpec());
813 ParseDeclarator(D);
814 return D.getInvalidType();
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000815 }
816
817 // It's not a type, it has to be an expression list.
818 // Discard the comma locations - ActOnCXXNew has enough parameters.
819 CommaLocsTy CommaLocs;
820 return ParseExpressionList(PlacementArgs, CommaLocs);
821}
822
823/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used
824/// to free memory allocated by new.
825///
Chris Lattnere7de3612009-01-04 21:25:24 +0000826/// This method is called to parse the 'delete' expression after the optional
827/// '::' has been already parsed. If the '::' was present, "UseGlobal" is true
828/// and "Start" is its location. Otherwise, "Start" is the location of the
829/// 'delete' token.
830///
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000831/// delete-expression:
832/// '::'[opt] 'delete' cast-expression
833/// '::'[opt] 'delete' '[' ']' cast-expression
Chris Lattnere7de3612009-01-04 21:25:24 +0000834Parser::OwningExprResult
835Parser::ParseCXXDeleteExpression(bool UseGlobal, SourceLocation Start) {
836 assert(Tok.is(tok::kw_delete) && "Expected 'delete' keyword");
837 ConsumeToken(); // Consume 'delete'
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000838
839 // Array delete?
840 bool ArrayDelete = false;
841 if (Tok.is(tok::l_square)) {
842 ArrayDelete = true;
843 SourceLocation LHS = ConsumeBracket();
844 SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS);
845 if (RHS.isInvalid())
Sebastian Redl39d4f022008-12-11 22:51:44 +0000846 return ExprError();
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000847 }
848
Sebastian Redl14ca7412008-12-11 21:36:32 +0000849 OwningExprResult Operand(ParseCastExpression(false));
Sebastian Redlbb4dae72008-12-09 13:15:23 +0000850 if (Operand.isInvalid())
Sebastian Redl39d4f022008-12-11 22:51:44 +0000851 return move(Operand);
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000852
Sebastian Redl39d4f022008-12-11 22:51:44 +0000853 return Owned(Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete,
854 Operand.release()));
Sebastian Redl19fec9d2008-11-21 19:14:01 +0000855}