[cfe-commits] r59835 - in /cfe/trunk: Driver/PrintParserCallbacks.cpp include/clang/AST/ExprCXX.h include/clang/AST/StmtNodes.def include/clang/Basic/DiagnosticKinds.def include/clang/Parse/Action.h include/clang/Parse/Parser.h lib/AST/Expr.cpp lib/AST/ExprCXX.cpp lib/AST/StmtPrinter.cpp lib/AST/StmtSerialization.cpp lib/Parse/ParseDecl.cpp lib/Parse/ParseExpr.cpp lib/Parse/ParseExprCXX.cpp lib/Sema/Sema.h lib/Sema/SemaExprCXX.cpp lib/Sema/SemaType.cpp test/SemaCXX/new-delete.cpp

Sebastian Redl sebastian.redl at getdesigned.at
Fri Nov 21 11:14:01 PST 2008


Author: cornedbee
Date: Fri Nov 21 13:14:01 2008
New Revision: 59835

URL: http://llvm.org/viewvc/llvm-project?rev=59835&view=rev
Log:
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.

Added:
    cfe/trunk/test/SemaCXX/new-delete.cpp
Modified:
    cfe/trunk/Driver/PrintParserCallbacks.cpp
    cfe/trunk/include/clang/AST/ExprCXX.h
    cfe/trunk/include/clang/AST/StmtNodes.def
    cfe/trunk/include/clang/Basic/DiagnosticKinds.def
    cfe/trunk/include/clang/Parse/Action.h
    cfe/trunk/include/clang/Parse/Parser.h
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprCXX.cpp
    cfe/trunk/lib/AST/StmtPrinter.cpp
    cfe/trunk/lib/AST/StmtSerialization.cpp
    cfe/trunk/lib/Parse/ParseDecl.cpp
    cfe/trunk/lib/Parse/ParseExpr.cpp
    cfe/trunk/lib/Parse/ParseExprCXX.cpp
    cfe/trunk/lib/Sema/Sema.h
    cfe/trunk/lib/Sema/SemaExprCXX.cpp
    cfe/trunk/lib/Sema/SemaType.cpp

Modified: cfe/trunk/Driver/PrintParserCallbacks.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/PrintParserCallbacks.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/Driver/PrintParserCallbacks.cpp (original)
+++ cfe/trunk/Driver/PrintParserCallbacks.cpp Fri Nov 21 13:14:01 2008
@@ -168,7 +168,7 @@
     // Type Parsing Callbacks.
     //===--------------------------------------------------------------------===//
   
-    virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+    virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
       llvm::cout << __FUNCTION__ << "\n";
       return 0;
     }

Modified: cfe/trunk/include/clang/AST/ExprCXX.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ExprCXX.h?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/ExprCXX.h (original)
+++ cfe/trunk/include/clang/AST/ExprCXX.h Fri Nov 21 13:14:01 2008
@@ -19,6 +19,8 @@
 
 namespace clang {
 
+  class CXXConstructorDecl;
+
 //===--------------------------------------------------------------------===//
 // C++ Expressions.
 //===--------------------------------------------------------------------===//
@@ -433,6 +435,184 @@
   //    CreateImpl(llvm::Deserializer& D, ASTContext& C);
 };
 
+/// CXXNewExpr - A new expression for memory allocation and constructor calls,
+/// e.g: "new CXXNewExpr(foo)".
+class CXXNewExpr : public Expr {
+  // Was the usage ::new, i.e. is the global new to be used?
+  bool GlobalNew : 1;
+  // Was the form (type-id) used? Otherwise, it was new-type-id.
+  bool ParenTypeId : 1;
+  // Is there an initializer? If not, built-ins are uninitialized, else they're
+  // value-initialized.
+  bool Initializer : 1;
+  // The number of placement new arguments.
+  unsigned NumPlacementArgs : 14;
+  // The number of constructor arguments. This may be 1 even for non-class
+  // types; use the pseudo copy constructor.
+  unsigned NumConstructorArgs : 15;
+  // Contains any number of optional placement arguments, and any number of
+  // optional constructor arguments, in that order.
+  Stmt **SubExprs;
+  // Points to the allocation function used.
+  FunctionDecl *OperatorNew;
+  // Points to the deallocation function used in case of error. May be null.
+  FunctionDecl *OperatorDelete;
+  // Points to the constructor used. Cannot be null if AllocType is a record;
+  // it would still point at the default constructor (even an implicit one).
+  // Must be null for all other types.
+  CXXConstructorDecl *Constructor;
+  // The type to be allocated. Is either *ty or a VLA of that type.
+  QualType AllocType;
+
+  SourceLocation StartLoc;
+  SourceLocation EndLoc;
+
+  // Deserialization constructor
+  CXXNewExpr(QualType ty, QualType alloc, bool globalNew, bool parenTypeId,
+             bool initializer, unsigned numPlacementArgs,
+             unsigned numConstructorArgs, Stmt **subExprs,
+             FunctionDecl *operatorNew, FunctionDecl *operatorDelete,
+             CXXConstructorDecl *constructor, SourceLocation startLoc,
+             SourceLocation endLoc)
+    : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
+      Initializer(initializer), NumPlacementArgs(numPlacementArgs),
+      NumConstructorArgs(numConstructorArgs), SubExprs(subExprs),
+      OperatorNew(operatorNew), OperatorDelete(operatorDelete),
+      Constructor(constructor), AllocType(alloc),
+      StartLoc(startLoc), EndLoc(endLoc)
+  { }
+public:
+  CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
+             unsigned numPlaceArgs, bool ParenTypeId, QualType alloc,
+             CXXConstructorDecl *constructor, bool initializer,
+             Expr **constructorArgs, unsigned numConsArgs,
+             FunctionDecl *operatorDelete, QualType ty,
+             SourceLocation startLoc, SourceLocation endLoc);
+  ~CXXNewExpr() {
+    delete[] SubExprs;
+  }
+
+  QualType getAllocatedType() const { return AllocType; }
+
+  FunctionDecl *getOperatorNew() const { return OperatorNew; }
+  FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+  CXXConstructorDecl *getConstructor() const { return Constructor; }
+
+  unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
+  Expr *getPlacementArg(unsigned i) {
+    assert(i < NumPlacementArgs && "Index out of range");
+    return cast<Expr>(SubExprs[i]);
+  }
+  const Expr *getPlacementArg(unsigned i) const {
+    assert(i < NumPlacementArgs && "Index out of range");
+    return cast<Expr>(SubExprs[i]);
+  }
+
+  bool isGlobalNew() const { return GlobalNew; }
+  bool isParenTypeId() const { return ParenTypeId; }
+  bool hasInitializer() const { return Initializer; }
+
+  unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
+  Expr *getConstructorArg(unsigned i) {
+    assert(i < NumConstructorArgs && "Index out of range");
+    return cast<Expr>(SubExprs[NumPlacementArgs + i]);
+  }
+  const Expr *getConstructorArg(unsigned i) const {
+    assert(i < NumConstructorArgs && "Index out of range");
+    return cast<Expr>(SubExprs[NumPlacementArgs + i]);
+  }
+
+  typedef ExprIterator arg_iterator;
+  typedef ConstExprIterator const_arg_iterator;
+
+  arg_iterator placement_arg_begin() {
+    return SubExprs;
+  }
+  arg_iterator placement_arg_end() {
+    return SubExprs + getNumPlacementArgs();
+  }
+  const_arg_iterator placement_arg_begin() const {
+    return SubExprs;
+  }
+  const_arg_iterator placement_arg_end() const {
+    return SubExprs + getNumPlacementArgs();
+  }
+
+  arg_iterator constructor_arg_begin() {
+    return SubExprs + getNumPlacementArgs();
+  }
+  arg_iterator constructor_arg_end() {
+    return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
+  }
+  const_arg_iterator constructor_arg_begin() const {
+    return SubExprs + getNumPlacementArgs();
+  }
+  const_arg_iterator constructor_arg_end() const {
+    return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
+  }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(StartLoc, EndLoc);
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXNewExprClass;
+  }
+  static bool classof(const CXXNewExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static CXXNewExpr* CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
+/// CXXDeleteExpr - A delete expression for memory deallocation and destructor
+/// calls, e.g. "delete[] pArray".
+class CXXDeleteExpr : public Expr {
+  // Is this a forced global delete, i.e. "::delete"?
+  bool GlobalDelete : 1;
+  // Is this the array form of delete, i.e. "delete[]"?
+  bool ArrayForm : 1;
+  // Points to the operator delete overload that is used. Could be a member.
+  FunctionDecl *OperatorDelete;
+  // The pointer expression to be deleted.
+  Stmt *Argument;
+  // Location of the expression.
+  SourceLocation Loc;
+public:
+  CXXDeleteExpr(QualType ty, bool globalDelete, bool arrayForm,
+                FunctionDecl *operatorDelete, Expr *arg, SourceLocation loc)
+    : Expr(CXXDeleteExprClass, ty), GlobalDelete(globalDelete),
+      ArrayForm(arrayForm), OperatorDelete(operatorDelete), Argument(arg),
+      Loc(loc) { }
+
+  bool isGlobalDelete() const { return GlobalDelete; }
+  bool isArrayForm() const { return ArrayForm; }
+
+  FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
+
+  Expr *getArgument() { return cast<Expr>(Argument); }
+  const Expr *getArgument() const { return cast<Expr>(Argument); }
+
+  virtual SourceRange getSourceRange() const {
+    return SourceRange(Loc, Argument->getLocEnd());
+  }
+
+  static bool classof(const Stmt *T) {
+    return T->getStmtClass() == CXXDeleteExprClass;
+  }
+  static bool classof(const CXXDeleteExpr *) { return true; }
+
+  // Iterators
+  virtual child_iterator child_begin();
+  virtual child_iterator child_end();
+
+  virtual void EmitImpl(llvm::Serializer& S) const;
+  static CXXDeleteExpr * CreateImpl(llvm::Deserializer& D, ASTContext& C);
+};
+
 }  // end namespace clang
 
 #endif

Modified: cfe/trunk/include/clang/AST/StmtNodes.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/StmtNodes.def?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/StmtNodes.def (original)
+++ cfe/trunk/include/clang/AST/StmtNodes.def Fri Nov 21 13:14:01 2008
@@ -104,6 +104,8 @@
 STMT(CXXDefaultArgExpr      , Expr)
 STMT(CXXZeroInitValueExpr   , Expr)
 STMT(CXXConditionDeclExpr   , DeclRefExpr)
+STMT(CXXNewExpr             , Expr)
+STMT(CXXDeleteExpr          , Expr)
 
 // Obj-C Expressions.
 STMT(ObjCStringLiteral    , Expr)

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Fri Nov 21 13:14:01 2008
@@ -1189,6 +1189,20 @@
 // Other C++ expressions
 DIAG(err_need_header_before_typeid, ERROR,
      "you need to include <typeinfo> before using the 'typeid' operator")
+DIAG(err_new_function, ERROR,
+     "cannot allocate function type '%0' with new")
+DIAG(err_new_incomplete, ERROR,
+     "cannot allocate incomplete type '%0' with new")
+DIAG(err_new_reference, ERROR,
+     "cannot allocate reference type '%0' with new")
+DIAG(err_new_array_nonconst, ERROR,
+     "only the first dimension of an allocated array may be non-const")
+DIAG(err_new_uninitialized_const, ERROR,
+     "must provide an initializer if the allocated object is 'const'")
+DIAG(err_delete_operand, ERROR,
+     "cannot delete expression of type '%0'")
+DIAG(warn_delete_incomplete, WARNING,
+     "deleting pointer to incomplete type '%0' may cause undefined behaviour")
 
 DIAG(err_invalid_use_of_function_type, ERROR,
      "a function type is not allowed here")

Modified: cfe/trunk/include/clang/Parse/Action.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Action.h?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Action.h (original)
+++ cfe/trunk/include/clang/Parse/Action.h Fri Nov 21 13:14:01 2008
@@ -256,8 +256,12 @@
   //===--------------------------------------------------------------------===//
   // Type Parsing Callbacks.
   //===--------------------------------------------------------------------===//
-  
-  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
+
+  /// ActOnTypeName - A type-name (type-id in C++) was parsed.
+  /// CXXNewMode is a flag passed by the parser of C++ new-expressions. It
+  /// specifies that the outermost array (if any) must be treated as a VLA.
+  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D,
+                                   bool CXXNewMode = false) {
     return 0;
   }
   
@@ -746,6 +750,36 @@
     return 0;
   }
 
+  /// ActOnCXXNew - Parsed a C++ 'new' expression. UseGlobal is true if the
+  /// new was qualified (::new). In a full new like
+  /// @code new (p1, p2) type(c1, c2) @endcode
+  /// the p1 and p2 expressions will be in PlacementArgs and the c1 and c2
+  /// expressions in ConstructorArgs. If the type is a dynamic array, Ty will
+  /// be a variable-length array type, with the outermost dimension to be
+  /// allocated dynamically.
+  /// Example:
+  /// @code new int*[rand()][3] @endcode
+  /// Here, Ty will be a VLA with size "rand()" and element type "int*[3]".
+  virtual ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+                                 SourceLocation PlacementLParen,
+                                 ExprTy **PlacementArgs, unsigned NumPlaceArgs,
+                                 SourceLocation PlacementRParen,
+                                 bool ParenTypeId, SourceLocation TyStart,
+                                 TypeTy *Ty, SourceLocation TyEnd,
+                                 SourceLocation ConstructorLParen,
+                                 ExprTy **ConstructorArgs, unsigned NumConsArgs,
+                                 SourceLocation ConstructorRParen) {
+    return 0;
+  }
+
+  /// ActOnCXXDelete - Parsed a C++ 'delete' expression. UseGlobal is true if
+  /// the delete was qualified (::delete). ArrayForm is true if the array form
+  /// was used (delete[]).
+  virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
+                                    bool ArrayForm, ExprTy *Operand) {
+    return 0;
+  }
+
   //===---------------------------- C++ Classes ---------------------------===//
   /// ActOnBaseSpecifier - Parsed a base specifier
   virtual BaseResult ActOnBaseSpecifier(DeclTy *classdecl, 

Modified: cfe/trunk/include/clang/Parse/Parser.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/Parser.h?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/Parser.h (original)
+++ cfe/trunk/include/clang/Parse/Parser.h Fri Nov 21 13:14:01 2008
@@ -509,6 +509,14 @@
   bool ParseCXXTypeSpecifierSeq(DeclSpec &DS);
 
   //===--------------------------------------------------------------------===//
+  // C++ 5.3.4 and 5.3.5: C++ new and delete
+  ExprResult ParseCXXNewExpression();
+  TypeTy *ParseNewTypeId();
+  bool ParseExpressionListOrTypeId(ExprListTy &Exprs, TypeTy *&Ty);
+  void ParseDirectNewDeclarator(Declarator &D);
+  ExprResult ParseCXXDeleteExpression();
+
+  //===--------------------------------------------------------------------===//
   // C++ if/switch/while/for condition expression.
   ExprResult ParseCXXCondition();
 
@@ -730,7 +738,7 @@
   TPResult TryParseBracketDeclarator();
 
 
-  TypeTy *ParseTypeName();
+  TypeTy *ParseTypeName(bool CXXNewMode = false);
   AttributeList *ParseAttributes();
   void ParseTypeofSpecifier(DeclSpec &DS);
 
@@ -756,7 +764,10 @@
   
   /// ParseDeclarator - Parse and verify a newly-initialized declarator.
   void ParseDeclarator(Declarator &D);
-  void ParseDeclaratorInternal(Declarator &D, bool PtrOperator = false);
+  /// A function that parses a variant of direct-declarator.
+  typedef void (Parser::*DirectDeclParseFunction)(Declarator&);
+  void ParseDeclaratorInternal(Declarator &D,
+                               DirectDeclParseFunction DirectDeclParser);
   void ParseTypeQualifierListOpt(DeclSpec &DS);
   void ParseDirectDeclarator(Declarator &D);
   void ParseParenDeclarator(Declarator &D);

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri Nov 21 13:14:01 2008
@@ -329,7 +329,13 @@
 
   case CXXDefaultArgExprClass:
     return cast<CXXDefaultArgExpr>(this)->getExpr()->hasLocalSideEffect();
-  }     
+
+  case CXXNewExprClass:
+    // FIXME: In theory, there might be new expressions that don't have side
+    // effects (e.g. a placement new with an uninitialized POD).
+  case CXXDeleteExprClass:
+    return true;
+  }
 }
 
 /// DeclCanBeLvalue - Determine whether the given declaration can be
@@ -481,8 +487,6 @@
   case CXXTypeidExprClass:
     // C++ 5.2.8p1: The result of a typeid expression is an lvalue of ...
     return LV_Valid;
-  case CXXThisExprClass:
-    return LV_InvalidExpression;
   default:
     break;
   }

Modified: cfe/trunk/lib/AST/ExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprCXX.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/AST/ExprCXX.cpp (original)
+++ cfe/trunk/lib/AST/ExprCXX.cpp Fri Nov 21 13:14:01 2008
@@ -77,6 +77,39 @@
   return child_iterator();
 }
 
+// CXXNewExpr
+CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
+                       Expr **placementArgs, unsigned numPlaceArgs,
+                       bool parenTypeId, QualType alloc,
+                       CXXConstructorDecl *constructor, bool initializer,
+                       Expr **constructorArgs, unsigned numConsArgs,
+                       FunctionDecl *operatorDelete, QualType ty,
+                       SourceLocation startLoc, SourceLocation endLoc)
+  : Expr(CXXNewExprClass, ty), GlobalNew(globalNew), ParenTypeId(parenTypeId),
+    Initializer(initializer), NumPlacementArgs(numPlaceArgs),
+    NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
+    OperatorDelete(operatorDelete), Constructor(constructor), AllocType(alloc),
+    StartLoc(startLoc), EndLoc(endLoc)
+{
+  unsigned TotalSize = NumPlacementArgs + NumConstructorArgs;
+  SubExprs = new Stmt*[TotalSize];
+  unsigned i = 0;
+  for(unsigned j = 0; j < NumPlacementArgs; ++j)
+    SubExprs[i++] = placementArgs[j];
+  for(unsigned j = 0; j < NumConstructorArgs; ++j)
+    SubExprs[i++] = constructorArgs[j];
+  assert(i == TotalSize);
+}
+
+Stmt::child_iterator CXXNewExpr::child_begin() { return &SubExprs[0]; }
+Stmt::child_iterator CXXNewExpr::child_end() {
+  return &SubExprs[0] + getNumPlacementArgs() + getNumConstructorArgs();
+}
+
+// CXXDeleteExpr
+Stmt::child_iterator CXXDeleteExpr::child_begin() { return &Argument; }
+Stmt::child_iterator CXXDeleteExpr::child_end() { return &Argument+1; }
+
 OverloadedOperatorKind CXXOperatorCallExpr::getOperator() const {
   // All simple function calls (e.g. func()) are implicitly cast to pointer to
   // function. As a result, we try and obtain the DeclRefExpr from the 

Modified: cfe/trunk/lib/AST/StmtPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtPrinter.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/AST/StmtPrinter.cpp (original)
+++ cfe/trunk/lib/AST/StmtPrinter.cpp Fri Nov 21 13:14:01 2008
@@ -925,6 +925,49 @@
   PrintRawDecl(E->getVarDecl());
 }
 
+void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
+  if (E->isGlobalNew())
+    OS << "::";
+  OS << "new ";
+  unsigned NumPlace = E->getNumPlacementArgs();
+  if (NumPlace > 0) {
+    OS << "(";
+    PrintExpr(E->getPlacementArg(0));
+    for (unsigned i = 1; i < NumPlace; ++i) {
+      OS << ", ";
+      PrintExpr(E->getPlacementArg(i));
+    }
+    OS << ") ";
+  }
+  if (E->isParenTypeId())
+    OS << "(";
+  OS << E->getAllocatedType().getAsString();
+  if (E->isParenTypeId())
+    OS << ")";
+
+  if (E->hasInitializer()) {
+    OS << "(";
+    unsigned NumCons = E->getNumConstructorArgs();
+    if (NumCons > 0) {
+      PrintExpr(E->getConstructorArg(0));
+      for (unsigned i = 1; i < NumCons; ++i) {
+        OS << ", ";
+        PrintExpr(E->getConstructorArg(i));
+      }
+    }
+    OS << ")";
+  }
+}
+
+void StmtPrinter::VisitCXXDeleteExpr(CXXDeleteExpr *E) {
+  if (E->isGlobalDelete())
+    OS << "::";
+  OS << "delete ";
+  if (E->isArrayForm())
+    OS << "[] ";
+  PrintExpr(E->getArgument());
+}
+
 // Obj-C 
 
 void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {

Modified: cfe/trunk/lib/AST/StmtSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/StmtSerialization.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/AST/StmtSerialization.cpp (original)
+++ cfe/trunk/lib/AST/StmtSerialization.cpp Fri Nov 21 13:14:01 2008
@@ -227,6 +227,12 @@
 
     case CXXZeroInitValueExprClass:
       return CXXZeroInitValueExpr::CreateImpl(D, C);
+
+    case CXXNewExprClass:
+      return CXXNewExpr::CreateImpl(D, C);
+
+    case CXXDeleteExprClass:
+      return CXXDeleteExpr::CreateImpl(D, C);
   }
 }
 
@@ -1414,3 +1420,66 @@
   SourceLocation RParenLoc = SourceLocation::ReadVal(D);
   return new CXXZeroInitValueExpr(Ty, TyBeginLoc, RParenLoc);
 }
+
+void CXXNewExpr::EmitImpl(Serializer& S) const {
+  S.Emit(getType());
+  S.Emit(Initializer);
+  S.Emit(NumPlacementArgs);
+  S.Emit(NumConstructorArgs);
+  S.BatchEmitOwnedPtrs(NumPlacementArgs + NumConstructorArgs, SubExprs);
+  assert((OperatorNew == 0 || S.isRegistered(OperatorNew)) &&
+         (OperatorDelete == 0 || S.isRegistered(OperatorDelete)) &&
+         (Constructor == 0 || S.isRegistered(Constructor)) &&
+         "CXXNewExpr cannot own declarations");
+  S.EmitPtr(OperatorNew);
+  S.EmitPtr(OperatorDelete);
+  S.EmitPtr(Constructor);
+  S.Emit(AllocType);
+  S.Emit(StartLoc);
+  S.Emit(EndLoc);
+}
+
+CXXNewExpr *
+CXXNewExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+  QualType T = QualType::ReadVal(D);
+  bool GlobalNew = D.ReadBool();
+  bool ParenTypeId = D.ReadBool();
+  bool Initializer = D.ReadBool();
+  unsigned NumPlacementArgs = D.ReadInt();
+  unsigned NumConstructorArgs = D.ReadInt();
+  unsigned TotalExprs = NumPlacementArgs + NumConstructorArgs;
+  Stmt** SubExprs = new Stmt*[TotalExprs];
+  D.BatchReadOwnedPtrs(TotalExprs, SubExprs, C);
+  FunctionDecl *OperatorNew = D.ReadPtr<FunctionDecl>();
+  FunctionDecl *OperatorDelete = D.ReadPtr<FunctionDecl>();
+  CXXConstructorDecl *Constructor = D.ReadPtr<CXXConstructorDecl>();
+  QualType AllocType = QualType::ReadVal(D);
+  SourceLocation StartLoc = SourceLocation::ReadVal(D);
+  SourceLocation EndLoc = SourceLocation::ReadVal(D);
+
+  return new CXXNewExpr(T, AllocType, GlobalNew, ParenTypeId, Initializer,
+                        NumPlacementArgs, NumConstructorArgs, SubExprs,
+                        OperatorNew, OperatorDelete, Constructor, StartLoc,
+                        EndLoc);
+}
+
+void CXXDeleteExpr::EmitImpl(Serializer& S) const {
+  S.Emit(getType());
+  S.Emit(GlobalDelete);
+  S.Emit(ArrayForm);
+  S.EmitPtr(OperatorDelete);
+  S.EmitOwnedPtr(Argument);
+  S.Emit(Loc);
+}
+
+CXXDeleteExpr *
+CXXDeleteExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+  QualType Ty = QualType::ReadVal(D);
+  bool GlobalDelete = D.ReadBool();
+  bool ArrayForm = D.ReadBool();
+  FunctionDecl *OperatorDelete = D.ReadPtr<FunctionDecl>();
+  Stmt *Argument = D.ReadOwnedPtr<Stmt>(C);
+  SourceLocation Loc = SourceLocation::ReadVal(D);
+  return new CXXDeleteExpr(Ty, GlobalDelete, ArrayForm, OperatorDelete,
+                           cast<Expr>(Argument), Loc);
+}

Modified: cfe/trunk/lib/Parse/ParseDecl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseDecl.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseDecl.cpp (original)
+++ cfe/trunk/lib/Parse/ParseDecl.cpp Fri Nov 21 13:14:01 2008
@@ -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);
 

Modified: cfe/trunk/lib/Parse/ParseExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExpr.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExpr.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExpr.cpp Fri Nov 21 13:14:01 2008
@@ -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);

Modified: cfe/trunk/lib/Parse/ParseExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Parse/ParseExprCXX.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Parse/ParseExprCXX.cpp (original)
+++ cfe/trunk/lib/Parse/ParseExprCXX.cpp Fri Nov 21 13:14:01 2008
@@ -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);
+}

Modified: cfe/trunk/lib/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/Sema.h?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/Sema.h (original)
+++ cfe/trunk/lib/Sema/Sema.h Fri Nov 21 13:14:01 2008
@@ -238,14 +238,16 @@
   //
   QualType ConvertDeclSpecToType(const DeclSpec &DS);
   void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
-  QualType GetTypeForDeclarator(Declarator &D, Scope *S);
+  QualType GetTypeForDeclarator(Declarator &D, Scope *S,
+                                bool CXXNewMode = false);
   DeclarationName GetNameForDeclarator(Declarator &D);
 
   QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
 
   bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
 
-  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
+  virtual TypeResult ActOnTypeName(Scope *S, Declarator &D,
+                                   bool CXXNewMode = false);
 
   //===--------------------------------------------------------------------===//
   // Symbol table / Decl tracking callbacks: SemaDecl.cpp.
@@ -805,6 +807,23 @@
                                                SourceLocation *CommaLocs,
                                                SourceLocation RParenLoc);
 
+  /// ActOnCXXNew - Parsed a C++ 'new' expression.
+  virtual ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+                                 SourceLocation PlacementLParen,
+                                 ExprTy **PlacementArgs, unsigned NumPlaceArgs,
+                                 SourceLocation PlacementRParen,
+                                 bool ParenTypeId, SourceLocation TyStart,
+                                 TypeTy *Ty, SourceLocation TyEnd,
+                                 SourceLocation ConstructorLParen,
+                                 ExprTy **ConstructorArgs, unsigned NumConsArgs,
+                                 SourceLocation ConstructorRParen);
+  bool CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
+                          const SourceRange &TyR);
+
+  /// ActOnCXXDelete - Parsed a C++ 'delete' expression
+  virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
+                                    bool ArrayForm, ExprTy *Operand);
+
   /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
   /// C++ if/switch/while/for statement.
   /// e.g: "if (int x = f()) {...}"

Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Fri Nov 21 13:14:01 2008
@@ -170,6 +170,200 @@
 }
 
 
+/// ActOnCXXNew - Parsed a C++ 'new' expression (C++ 5.3.4), as in e.g.:
+/// @code new (memory) int[size][4] @endcode
+/// or
+/// @code ::new Foo(23, "hello") @endcode
+/// For the interpretation of this heap of arguments, consult the base version.
+Action::ExprResult
+Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
+                  SourceLocation PlacementLParen,
+                  ExprTy **PlacementArgs, unsigned NumPlaceArgs,
+                  SourceLocation PlacementRParen, bool ParenTypeId,
+                  SourceLocation TyStart, TypeTy *Ty, SourceLocation TyEnd,
+                  SourceLocation ConstructorLParen,
+                  ExprTy **ConstructorArgs, unsigned NumConsArgs,
+                  SourceLocation ConstructorRParen)
+{
+  QualType AllocType = QualType::getFromOpaquePtr(Ty);
+  QualType CheckType = AllocType;
+  // To leverage the existing parser as much as possible, array types are
+  // parsed as VLAs. Unwrap for checking.
+  if (const VariableArrayType *VLA = Context.getAsVariableArrayType(AllocType)){
+    CheckType = VLA->getElementType();
+  }
+
+  // Validate the type, and unwrap an array if any.
+  if (CheckAllocatedType(CheckType, StartLoc, SourceRange(TyStart, TyEnd)))
+    return true;
+
+  QualType ResultType = Context.getPointerType(CheckType);
+
+  // That every array dimension except the first is constant was already
+  // checked by the type check above.
+  // C++ 5.3.4p6: "The expression in a direct-new-declarator shall have integral
+  //   or enumeration type with a non-negative value."
+  // This was checked by ActOnTypeName, since C99 has the same restriction on
+  // VLA expressions.
+
+  // --- Choosing an allocation function ---
+  // C++ 5.3.4p8 - 14 & 18
+  // 1) If UseGlobal is true, only look in the global scope. Else, also look
+  //   in the scope of the allocated class.
+  // 2) If an array size is given, look for operator new[], else look for
+  //   operator new.
+  // 3) The first argument is always size_t. Append the arguments from the
+  //   placement form.
+  // FIXME: Find the correct overload of operator new.
+  // FIXME: Also find the corresponding overload of operator delete.
+  FunctionDecl *OperatorNew = 0;
+  FunctionDecl *OperatorDelete = 0;
+  Expr **PlaceArgs = (Expr**)PlacementArgs;
+
+  bool Init = ConstructorLParen.isValid();
+  // --- Choosing a constructor ---
+  // C++ 5.3.4p15
+  // 1) If T is a POD and there's no initializer (ConstructorLParen is invalid)
+  //   the object is not initialized. If the object, or any part of it, is
+  //   const-qualified, it's an error.
+  // 2) If T is a POD and there's an empty initializer, the object is value-
+  //   initialized.
+  // 3) If T is a POD and there's one initializer argument, the object is copy-
+  //   constructed.
+  // 4) If T is a POD and there's more initializer arguments, it's an error.
+  // 5) If T is not a POD, the initializer arguments are used as constructor
+  //   arguments.
+  //
+  // Or by the C++0x formulation:
+  // 1) If there's no initializer, the object is default-initialized according
+  //    to C++0x rules.
+  // 2) Otherwise, the object is direct-initialized.
+  CXXConstructorDecl *Constructor = 0;
+  Expr **ConsArgs = (Expr**)ConstructorArgs;
+  if (CheckType->isRecordType()) {
+    // FIXME: This is incorrect for when there is an empty initializer and
+    // no user-defined constructor. Must zero-initialize, not default-construct.
+    Constructor = PerformInitializationByConstructor(
+                      CheckType, ConsArgs, NumConsArgs,
+                      TyStart, SourceRange(TyStart, ConstructorRParen),
+                      CheckType.getAsString(),
+                      NumConsArgs != 0 ? IK_Direct : IK_Default);
+    if (!Constructor)
+      return true;
+  } else {
+    if (!Init) {
+      // FIXME: Check that no subpart is const.
+      if (CheckType.isConstQualified()) {
+        Diag(StartLoc, diag::err_new_uninitialized_const)
+          << SourceRange(StartLoc, TyEnd);
+        return true;
+      }
+    } else if (NumConsArgs == 0) {
+      // Object is value-initialized. Do nothing.
+    } else if (NumConsArgs == 1) {
+      // Object is direct-initialized.
+      if (CheckInitializerTypes(ConsArgs[0], CheckType, StartLoc,
+                                CheckType.getAsString()))
+        return true;
+    } else {
+      Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg)
+        << SourceRange(ConstructorLParen, ConstructorRParen);
+    }
+  }
+
+  // FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
+
+  return new CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs,
+                        ParenTypeId, AllocType, Constructor, Init,
+                        ConsArgs, NumConsArgs, OperatorDelete, ResultType,
+                        StartLoc, Init ? ConstructorRParen : TyEnd);
+}
+
+/// CheckAllocatedType - Checks that a type is suitable as the allocated type
+/// in a new-expression.
+/// dimension off and stores the size expression in ArraySize.
+bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
+                              const SourceRange &TyR)
+{
+  // C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
+  //   abstract class type or array thereof.
+  // FIXME: We don't have abstract types yet.
+  // FIXME: Under C++ semantics, an incomplete object type is still an object
+  // type. This code assumes the C semantics, where it's not.
+  if (!AllocType->isObjectType()) {
+    diag::kind msg;
+    if (AllocType->isFunctionType()) {
+      msg = diag::err_new_function;
+    } else if(AllocType->isIncompleteType()) {
+      msg = diag::err_new_incomplete;
+    } else if(AllocType->isReferenceType()) {
+      msg = diag::err_new_reference;
+    } else {
+      assert(false && "Unexpected type class");
+      return true;
+    }
+    Diag(StartLoc, msg) << AllocType.getAsString() << TyR;
+    return true;
+  }
+
+  // Every dimension beyond the first shall be of constant size.
+  while (const ArrayType *Array = Context.getAsArrayType(AllocType)) {
+    if (!Array->isConstantArrayType()) {
+      // FIXME: Might be nice to get a better source range from somewhere.
+      Diag(StartLoc, diag::err_new_array_nonconst) << TyR;
+      return true;
+    }
+    AllocType = Array->getElementType();
+  }
+
+  return false;
+}
+
+/// ActOnCXXDelete - Parsed a C++ 'delete' expression (C++ 5.3.5), as in:
+/// @code ::delete ptr; @endcode
+/// or
+/// @code delete [] ptr; @endcode
+Action::ExprResult
+Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
+                     bool ArrayForm, ExprTy *Operand)
+{
+  // C++ 5.3.5p1: "The operand shall have a pointer type, or a class type
+  //   having a single conversion function to a pointer type. The result has
+  //   type void."
+  // DR599 amends "pointer type" to "pointer to object type" in both cases.
+
+  Expr *Ex = (Expr *)Operand;
+  QualType Type = Ex->getType();
+
+  if (Type->isRecordType()) {
+    // FIXME: Find that one conversion function and amend the type.
+  }
+
+  if (!Type->isPointerType()) {
+    Diag(StartLoc, diag::err_delete_operand)
+      << Type.getAsString() << Ex->getSourceRange();
+    return true;
+  }
+
+  QualType Pointee = Type->getAsPointerType()->getPointeeType();
+  if (Pointee->isIncompleteType() && !Pointee->isVoidType())
+    Diag(StartLoc, diag::warn_delete_incomplete)
+      << Pointee.getAsString() << Ex->getSourceRange();
+  else if (!Pointee->isObjectType()) {
+    Diag(StartLoc, diag::err_delete_operand)
+      << Type.getAsString() << Ex->getSourceRange();
+    return true;
+  }
+
+  // FIXME: Look up the correct operator delete overload and pass a pointer
+  // along.
+  // FIXME: Check access and ambiguity of operator delete and destructor.
+
+  return new CXXDeleteExpr(Context.VoidTy, UseGlobal, ArrayForm, 0, Ex,
+                           StartLoc);
+}
+
+
 /// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
 /// C++ if/switch/while/for statement.
 /// e.g: "if (int x = f()) {...}"

Modified: cfe/trunk/lib/Sema/SemaType.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaType.cpp?rev=59835&r1=59834&r2=59835&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaType.cpp (original)
+++ cfe/trunk/lib/Sema/SemaType.cpp Fri Nov 21 13:14:01 2008
@@ -250,14 +250,14 @@
 
 /// GetTypeForDeclarator - Convert the type for the specified declarator to Type
 /// instances.
-QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {
+QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
   // long long is a C99 feature.
   if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
       D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
     Diag(D.getDeclSpec().getTypeSpecWidthLoc(), diag::ext_longlong);
   
   QualType T = ConvertDeclSpecToType(D.getDeclSpec());
-  
+
   // Walk the DeclTypeInfo, building the recursive type as we go.  DeclTypeInfos
   // are ordered from the identifier out, which is opposite of what we want :).
   for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) {
@@ -340,6 +340,8 @@
       break;
     }
     case DeclaratorChunk::Array: {
+      // Only the outermost dimension gets special treatment.
+      bool UseCXXNewMode = CXXNewMode && i == e-1;
       DeclaratorChunk::ArrayTypeInfo &ATI = DeclType.Arr;
       Expr *ArraySize = static_cast<Expr*>(ATI.NumElts);
       ArrayType::ArraySizeModifier ASM;
@@ -394,9 +396,11 @@
       if (!ArraySize) {
         T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
       } else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
-                 !T->isConstantSizeType()) {
+                 !T->isConstantSizeType() || UseCXXNewMode) {
         // Per C99, a variable array is an array with either a non-constant
         // size or an element type that has a non-constant-size
+        // We also force this for parsing C++ new-expressions, since the
+        // outermost dimension is always treated as variable.
         T = Context.getVariableArrayType(T, ArraySize, ASM, ATI.TypeQuals);
       } else {
         // C99 6.7.5.2p1: If the expression is a constant expression, it shall
@@ -416,7 +420,9 @@
         T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals);
       }
       // If this is not C99, extwarn about VLA's and C99 array size modifiers.
-      if (!getLangOptions().C99 && 
+      // Unless we're in C++ new mode. ActOnCXXNew will complain about them
+      // there, and they're hard errors.
+      if (!getLangOptions().C99 && !CXXNewMode &&
           (ASM != ArrayType::Normal ||
            (ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
         Diag(D.getIdentifierLoc(), diag::ext_vla);
@@ -614,12 +620,12 @@
   return false;
 }
 
-Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
+Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
   // C99 6.7.6: Type names have no identifier.  This is already validated by
   // the parser.
   assert(D.getIdentifier() == 0 && "Type name should have no identifier!");
   
-  QualType T = GetTypeForDeclarator(D, S);
+  QualType T = GetTypeForDeclarator(D, S, CXXNewMode);
 
   assert(!T.isNull() && "GetTypeForDeclarator() returned null type");
   

Added: cfe/trunk/test/SemaCXX/new-delete.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/new-delete.cpp?rev=59835&view=auto

==============================================================================
--- cfe/trunk/test/SemaCXX/new-delete.cpp (added)
+++ cfe/trunk/test/SemaCXX/new-delete.cpp Fri Nov 21 13:14:01 2008
@@ -0,0 +1,56 @@
+struct S // expected-note {{candidate}}
+{
+  S(int, int, double); // expected-note {{candidate}}
+  S(double, int); // expected-note {{candidate}} expected-note {{candidate}}
+  S(float, int); // expected-note {{candidate}} expected-note {{candidate}}
+};
+struct T;
+
+void good_news()
+{
+  int *pi = new int;
+  float *pf = new (pi) float();
+  pi = new int(1);
+  pi = new int('c');
+  const int *pci = new const int();
+  S *ps = new S(1, 2, 3.4);
+  ps = new (pf) S(1, 2, 3.4);
+  S *(*paps)[2] = new S*[*pi][2];
+  ps = new (S[3])(1, 2, 3.4);
+  typedef int ia4[4];
+  ia4 *pai = new (int[3][4]);
+}
+
+void bad_news()
+{
+  int i = 1;
+  (void)new; // expected-error {{missing type specifier}}
+  (void)new 4; // expected-error {{missing type specifier}}
+  (void)new () int; // expected-error {{expected expression}}
+  (void)new int[1.1]; // expected-error {{size of array has non-integer type}}
+  (void)new int[1][i]; // expected-error {{only the first dimension}}
+  (void)new (int[1][i]); // expected-error {{only the first dimension}}
+  (void)new int(*(S*)0); // expected-error {{incompatible type initializing}}
+  (void)new int(1, 2); // expected-error {{initializer of a builtin type can only take one argument}}
+  (void)new S(1); // expected-error {{no matching constructor}}
+  (void)new S(1, 1); // expected-error {{call to constructor of 'struct S' is ambiguous}}
+  (void)new const int; // expected-error {{must provide an initializer}}
+  
+  // Some lacking cases due to lack of sema support.
+}
+
+void good_deletes()
+{
+  delete (int*)0;
+  delete [](int*)0;
+  delete (S*)0;
+}
+
+void bad_deletes()
+{
+  delete 0; // expected-error {{cannot delete expression of type 'int'}}
+  delete [0] (int*)0; // expected-error {{expected ']'}} \
+                      // expected-error {{to match this '['}}
+  delete (void*)0; // expected-error {{cannot delete expression}}
+  delete (T*)0; // expected-warning {{deleting pointer to incomplete type}}
+}





More information about the cfe-commits mailing list