diff options
Diffstat (limited to 'clang/lib/Parse')
| -rw-r--r-- | clang/lib/Parse/ParseDecl.cpp | 31 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExpr.cpp | 19 | ||||
| -rw-r--r-- | clang/lib/Parse/ParseExprCXX.cpp | 228 |
3 files changed, 264 insertions, 14 deletions
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 92a5fdb9291..3262c0de1c2 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -25,7 +25,11 @@ using namespace clang; /// ParseTypeName /// type-name: [C99 6.7.6] /// specifier-qualifier-list abstract-declarator[opt] -Parser::TypeTy *Parser::ParseTypeName() { +/// +/// Called type-id in C++. +/// CXXNewMode is a special flag used by the parser of C++ new-expressions. It +/// is simply passed on to ActOnTypeName. +Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) { // Parse the common declaration-specifiers piece. DeclSpec DS; ParseSpecifierQualifierList(DS); @@ -34,7 +38,7 @@ Parser::TypeTy *Parser::ParseTypeName() { Declarator DeclaratorInfo(DS, Declarator::TypeNameContext); ParseDeclarator(DeclaratorInfo); - return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val; + return Actions.ActOnTypeName(CurScope, DeclaratorInfo, CXXNewMode).Val; } /// ParseAttributes - Parse a non-empty attributes list. @@ -1292,12 +1296,12 @@ void Parser::ParseTypeQualifierListOpt(DeclSpec &DS) { void Parser::ParseDeclarator(Declarator &D) { /// This implements the 'declarator' production in the C grammar, then checks /// for well-formedness and issues diagnostics. - ParseDeclaratorInternal(D); + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); } -/// ParseDeclaratorInternal - Parse a C or C++ declarator. If -/// PtrOperator is true, then this routine won't parse the final -/// direct-declarator; therefore, it effectively parses the C++ +/// ParseDeclaratorInternal - Parse a C or C++ declarator. The direct-declarator +/// is parsed by the function passed to it. Pass null, and the direct-declarator +/// isn't parsed at all, making this function effectively parse the C++ /// ptr-operator production. /// /// declarator: [C99 6.7.5] @@ -1314,14 +1318,15 @@ void Parser::ParseDeclarator(Declarator &D) { /// '&' /// [GNU] '&' restrict[opt] attributes[opt] /// '::'[opt] nested-name-specifier '*' cv-qualifier-seq[opt] [TODO] -void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { +void Parser::ParseDeclaratorInternal(Declarator &D, + DirectDeclParseFunction DirectDeclParser) { tok::TokenKind Kind = Tok.getKind(); // Not a pointer, C++ reference, or block. if (Kind != tok::star && (Kind != tok::amp || !getLang().CPlusPlus) && (Kind != tok::caret || !getLang().Blocks)) { - if (!PtrOperator) - ParseDirectDeclarator(D); + if (DirectDeclParser) + (this->*DirectDeclParser)(D); return; } @@ -1335,7 +1340,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { ParseTypeQualifierListOpt(DS); // Recursively parse the declarator. - ParseDeclaratorInternal(D, PtrOperator); + ParseDeclaratorInternal(D, DirectDeclParser); if (Kind == tok::star) // Remember that we parsed a pointer type, and remember the type-quals. D.AddTypeInfo(DeclaratorChunk::getPointer(DS.getTypeQualifiers(), Loc, @@ -1366,7 +1371,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { } // Recursively parse the declarator. - ParseDeclaratorInternal(D, PtrOperator); + ParseDeclaratorInternal(D, DirectDeclParser); if (D.getNumTypeObjects() > 0) { // C++ [dcl.ref]p4: There shall be no references to references. @@ -1379,7 +1384,7 @@ void Parser::ParseDeclaratorInternal(Declarator &D, bool PtrOperator) { Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference) << "type name"; - // Once we've complained about the reference-to-referwnce, we + // Once we've complained about the reference-to-reference, we // can go ahead and build the (technically ill-formed) // declarator: reference collapsing will take care of it. } @@ -1581,7 +1586,7 @@ void Parser::ParseParenDeclarator(Declarator &D) { if (AttrList) D.AddAttributes(AttrList); - ParseDeclaratorInternal(D); + ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator); // Match the ')'. MatchRHSPunctuation(tok::r_paren, StartLoc); diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp index 74b0715de2a..9f9b306c45f 100644 --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -351,6 +351,8 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { /// [GNU] '__alignof' '(' type-name ')' /// [C++0x] 'alignof' '(' type-id ')' /// [GNU] '&&' identifier +/// [C++] new-expression +/// [C++] delete-expression /// /// unary-operator: one of /// '&' '*' '+' '-' '~' '!' @@ -405,6 +407,16 @@ Parser::ParseRHSOfBinaryExpression(ExprResult LHS, unsigned MinPrec) { /// '~' class-name [TODO] /// template-id [TODO] /// +/// new-expression: [C++ 5.3.4] +/// '::'[opt] 'new' new-placement[opt] new-type-id +/// new-initializer[opt] +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// delete-expression: [C++ 5.3.5] +/// '::'[opt] 'delete' cast-expression +/// '::'[opt] 'delete' '[' ']' cast-expression +/// Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { if (getLang().CPlusPlus) { // Annotate typenames and C++ scope specifiers. @@ -614,6 +626,13 @@ Parser::ExprResult Parser::ParseCastExpression(bool isUnaryExpression) { Res = ParseCXXIdExpression(); return ParsePostfixExpressionSuffix(Res); + case tok::kw_new: // [C++] new-expression + // FIXME: ParseCXXIdExpression currently steals :: tokens. + return ParseCXXNewExpression(); + + case tok::kw_delete: // [C++] delete-expression + return ParseCXXDeleteExpression(); + case tok::at: { SourceLocation AtLoc = ConsumeToken(); return ParseObjCAtExpression(AtLoc); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 46c7a135e0f..9eb2431642a 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/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); +} |

