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
diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp
index 92a5fdb..3262c0d 100644
--- a/lib/Parse/ParseDecl.cpp
+++ b/lib/Parse/ParseDecl.cpp
@@ -25,7 +25,11 @@
 /// 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 @@
   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::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 @@
 ///         '&'
 /// [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 @@
     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 @@
     }
 
     // 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 @@
           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 @@
     if (AttrList)
       D.AddAttributes(AttrList);
 
-    ParseDeclaratorInternal(D);
+    ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
     // Match the ')'.
     MatchRHSPunctuation(tok::r_paren, StartLoc);
 
diff --git a/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp
index 74b0715..9f9b306 100644
--- a/lib/Parse/ParseExpr.cpp
+++ b/lib/Parse/ParseExpr.cpp
@@ -351,6 +351,8 @@
 /// [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 @@
 ///                   '~' 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 @@
     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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp
index 46c7a13..9eb2431 100644
--- a/lib/Parse/ParseExprCXX.cpp
+++ b/lib/Parse/ParseExprCXX.cpp
@@ -614,7 +614,7 @@
   // 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 @@
   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);
+}