diff options
author | Sebastian Redl <sebastian.redl@getdesigned.at> | 2008-11-21 19:14:01 +0000 |
---|---|---|
committer | Sebastian Redl <sebastian.redl@getdesigned.at> | 2008-11-21 19:14:01 +0000 |
commit | 4c5d320a7581f4b80b151630c91cea5727fa9923 (patch) | |
tree | 2ebb368fb49a811cb48d60dbda245007efb6d8b5 /lib/Parse/ParseExprCXX.cpp | |
parent | 730e0fdbbf9b315ef834074054ac55af3a4fcc0c (diff) |
Implementation of new and delete parsing and sema.
This version uses VLAs to represent arrays. I'll try an alternative way next, but I want this safe first.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@59835 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Parse/ParseExprCXX.cpp')
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 228 |
1 files changed, 227 insertions, 1 deletions
diff --git a/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 46c7a135e0..9eb2431642 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -614,7 +614,7 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() { // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. Declarator D(DS, Declarator::TypeNameContext); - ParseDeclaratorInternal(D, /*PtrOperator=*/true); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D); @@ -623,3 +623,229 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() { else return Result.Val; } + +/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate +/// memory in a typesafe manner and call constructors. +/// +/// new-expression: +/// '::'[opt] 'new' new-placement[opt] new-type-id +/// new-initializer[opt] +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// new-placement: +/// '(' expression-list ')' +/// +/// new-initializer: +/// '(' expression-list[opt] ')' +/// [C++0x] braced-init-list [TODO] +/// +Parser::ExprResult Parser::ParseCXXNewExpression() +{ + assert((Tok.is(tok::coloncolon) || Tok.is(tok::kw_new)) && + "Expected :: or 'new' keyword"); + + SourceLocation Start = Tok.getLocation(); + bool UseGlobal = false; + if (Tok.is(tok::coloncolon)) { + UseGlobal = true; + ConsumeToken(); + } + + assert(Tok.is(tok::kw_new) && "Lookahead should have ensured 'new'"); + // Consume 'new' + ConsumeToken(); + + // A '(' now can be a new-placement or the '(' wrapping the type-id in the + // second form of new-expression. It can't be a new-type-id. + + ExprListTy PlacementArgs; + SourceLocation PlacementLParen, PlacementRParen; + + TypeTy *Ty = 0; + SourceLocation TyStart, TyEnd; + bool ParenTypeId; + if (Tok.is(tok::l_paren)) { + // If it turns out to be a placement, we change the type location. + PlacementLParen = ConsumeParen(); + TyStart = Tok.getLocation(); + if (ParseExpressionListOrTypeId(PlacementArgs, Ty)) + return true; + TyEnd = Tok.getLocation(); + + PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen); + if (PlacementRParen.isInvalid()) + return true; + + if (Ty) { + // Reset the placement locations. There was no placement. + PlacementLParen = PlacementRParen = SourceLocation(); + ParenTypeId = true; + } else { + // We still need the type. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + TyStart = Tok.getLocation(); + Ty = ParseTypeName(/*CXXNewMode=*/true); + ParenTypeId = true; + } else { + TyStart = Tok.getLocation(); + Ty = ParseNewTypeId(); + ParenTypeId = false; + } + if (!Ty) + return true; + TyEnd = Tok.getLocation(); + } + } else { + TyStart = Tok.getLocation(); + Ty = ParseNewTypeId(); + if (!Ty) + return true; + TyEnd = Tok.getLocation(); + ParenTypeId = false; + } + + ExprListTy ConstructorArgs; + SourceLocation ConstructorLParen, ConstructorRParen; + + if (Tok.is(tok::l_paren)) { + ConstructorLParen = ConsumeParen(); + if (Tok.isNot(tok::r_paren)) { + CommaLocsTy CommaLocs; + if (ParseExpressionList(ConstructorArgs, CommaLocs)) + return true; + } + ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen); + if (ConstructorRParen.isInvalid()) + return true; + } + + return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, + &PlacementArgs[0], PlacementArgs.size(), + PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd, + ConstructorLParen, &ConstructorArgs[0], + ConstructorArgs.size(), ConstructorRParen); +} + +/// ParseNewTypeId - Parses a type ID as it appears in a new expression. +/// The most interesting part of this is the new-declarator, which can be a +/// multi-dimensional array, of which the first has a non-constant expression as +/// the size, e.g. +/// @code new int[runtimeSize()][2][2] @endcode +/// +/// new-type-id: +/// type-specifier-seq new-declarator[opt] +/// +/// new-declarator: +/// ptr-operator new-declarator[opt] +/// direct-new-declarator +/// +Parser::TypeTy * Parser::ParseNewTypeId() +{ + DeclSpec DS; + if (ParseCXXTypeSpecifierSeq(DS)) + return 0; + + // A new-declarator is a simplified version of a declarator. We use + // ParseDeclaratorInternal, but pass our own direct declarator parser, + // one that parses a direct-new-declarator. + Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); + ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseDirectNewDeclarator); + + TypeTy *Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo, + /*CXXNewMode=*/true).Val; + return DeclaratorInfo.getInvalidType() ? 0 : Ty; +} + +/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be +/// passed to ParseDeclaratorInternal. +/// +/// direct-new-declarator: +/// '[' expression ']' +/// direct-new-declarator '[' constant-expression ']' +/// +void Parser::ParseDirectNewDeclarator(Declarator &D) +{ + // Parse the array dimensions. + bool first = true; + while (Tok.is(tok::l_square)) { + SourceLocation LLoc = ConsumeBracket(); + ExprResult Size = first ? ParseExpression() : ParseConstantExpression(); + if (Size.isInvalid) { + // Recover + SkipUntil(tok::r_square); + return; + } + first = false; + + D.AddTypeInfo(DeclaratorChunk::getArray(0, /*static=*/false, /*star=*/false, + Size.Val, LLoc)); + + if (MatchRHSPunctuation(tok::r_square, LLoc).isInvalid()) + return; + } +} + +/// ParseExpressionListOrTypeId - Parse either an expression-list or a type-id. +/// This ambiguity appears in the syntax of the C++ new operator. +/// +/// new-expression: +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// new-placement: +/// '(' expression-list ')' +/// +bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, TypeTy *&Ty) +{ + // The '(' was already consumed. + if (isTypeIdInParens()) { + Ty = ParseTypeName(/*CXXNewMode=*/true); + return Ty == 0; + } + + // It's not a type, it has to be an expression list. + // Discard the comma locations - ActOnCXXNew has enough parameters. + CommaLocsTy CommaLocs; + return ParseExpressionList(PlacementArgs, CommaLocs); +} + +/// ParseCXXDeleteExpression - Parse a C++ delete-expression. Delete is used +/// to free memory allocated by new. +/// +/// delete-expression: +/// '::'[opt] 'delete' cast-expression +/// '::'[opt] 'delete' '[' ']' cast-expression +Parser::ExprResult Parser::ParseCXXDeleteExpression() +{ + assert((Tok.is(tok::coloncolon) || Tok.is(tok::kw_delete)) && + "Expected :: or 'delete' keyword"); + + SourceLocation Start = Tok.getLocation(); + bool UseGlobal = false; + if (Tok.is(tok::coloncolon)) { + UseGlobal = true; + ConsumeToken(); + } + + assert(Tok.is(tok::kw_delete) && "Lookahead should have ensured 'delete'"); + // Consume 'delete' + ConsumeToken(); + + // Array delete? + bool ArrayDelete = false; + if (Tok.is(tok::l_square)) { + ArrayDelete = true; + SourceLocation LHS = ConsumeBracket(); + SourceLocation RHS = MatchRHSPunctuation(tok::r_square, LHS); + if (RHS.isInvalid()) + return true; + } + + ExprResult Operand = ParseCastExpression(false); + if (Operand.isInvalid) + return Operand; + + return Actions.ActOnCXXDelete(Start, UseGlobal, ArrayDelete, Operand.Val); +} |