diff options
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/Driver/PrintParserCallbacks.cpp | 2 | ||||
| -rw-r--r-- | clang/include/clang/AST/ExprCXX.h | 180 | ||||
| -rw-r--r-- | clang/include/clang/AST/StmtNodes.def | 2 | ||||
| -rw-r--r-- | clang/include/clang/Basic/DiagnosticKinds.def | 14 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Action.h | 38 | ||||
| -rw-r--r-- | clang/include/clang/Parse/Parser.h | 15 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 10 | ||||
| -rw-r--r-- | clang/lib/AST/ExprCXX.cpp | 33 | ||||
| -rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 43 | ||||
| -rw-r--r-- | clang/lib/AST/StmtSerialization.cpp | 69 | ||||
| -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 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 23 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExprCXX.cpp | 194 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 18 | ||||
| -rw-r--r-- | clang/test/SemaCXX/new-delete.cpp | 56 | 
17 files changed, 945 insertions, 30 deletions
diff --git a/clang/Driver/PrintParserCallbacks.cpp b/clang/Driver/PrintParserCallbacks.cpp index 2ee113fcda5..02203d356d4 100644 --- a/clang/Driver/PrintParserCallbacks.cpp +++ b/clang/Driver/PrintParserCallbacks.cpp @@ -168,7 +168,7 @@ namespace {      // 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;      } diff --git a/clang/include/clang/AST/ExprCXX.h b/clang/include/clang/AST/ExprCXX.h index c855089d8f5..201a9331db7 100644 --- a/clang/include/clang/AST/ExprCXX.h +++ b/clang/include/clang/AST/ExprCXX.h @@ -19,6 +19,8 @@  namespace clang { +  class CXXConstructorDecl; +  //===--------------------------------------------------------------------===//  // C++ Expressions.  //===--------------------------------------------------------------------===// @@ -433,6 +435,184 @@ public:    //    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 diff --git a/clang/include/clang/AST/StmtNodes.def b/clang/include/clang/AST/StmtNodes.def index beb64c51f31..6d3c172c96b 100644 --- a/clang/include/clang/AST/StmtNodes.def +++ b/clang/include/clang/AST/StmtNodes.def @@ -104,6 +104,8 @@ STMT(CXXThrowExpr           , Expr)  STMT(CXXDefaultArgExpr      , Expr)  STMT(CXXZeroInitValueExpr   , Expr)  STMT(CXXConditionDeclExpr   , DeclRefExpr) +STMT(CXXNewExpr             , Expr) +STMT(CXXDeleteExpr          , Expr)  // Obj-C Expressions.  STMT(ObjCStringLiteral    , Expr) diff --git a/clang/include/clang/Basic/DiagnosticKinds.def b/clang/include/clang/Basic/DiagnosticKinds.def index 6a85df0e186..4525355ba37 100644 --- a/clang/include/clang/Basic/DiagnosticKinds.def +++ b/clang/include/clang/Basic/DiagnosticKinds.def @@ -1189,6 +1189,20 @@ DIAG(err_static_downcast_via_virtual, ERROR,  // 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") diff --git a/clang/include/clang/Parse/Action.h b/clang/include/clang/Parse/Action.h index d00fbd33616..9a7b41b9e5c 100644 --- a/clang/include/clang/Parse/Action.h +++ b/clang/include/clang/Parse/Action.h @@ -256,8 +256,12 @@ public:    //===--------------------------------------------------------------------===//    // 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 @@ public:      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,  diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 0c061219f84..76edfc14146 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -509,6 +509,14 @@ private:    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 @@ private:    TPResult TryParseBracketDeclarator(); -  TypeTy *ParseTypeName(); +  TypeTy *ParseTypeName(bool CXXNewMode = false);    AttributeList *ParseAttributes();    void ParseTypeofSpecifier(DeclSpec &DS); @@ -756,7 +764,10 @@ private:    /// 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); diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index 2e13352a5ad..e6a7b4114a1 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -329,7 +329,13 @@ bool Expr::hasLocalSideEffect() const {    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 @@ Expr::isLvalueResult Expr::isLvalue(ASTContext &Ctx) const {    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;    } diff --git a/clang/lib/AST/ExprCXX.cpp b/clang/lib/AST/ExprCXX.cpp index 1155a4b9c6b..c0f2985f1e9 100644 --- a/clang/lib/AST/ExprCXX.cpp +++ b/clang/lib/AST/ExprCXX.cpp @@ -77,6 +77,39 @@ Stmt::child_iterator CXXConditionDeclExpr::child_end() {    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  diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index cf6d4c0b901..cb5c44f9269 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -925,6 +925,49 @@ StmtPrinter::VisitCXXConditionDeclExpr(CXXConditionDeclExpr *E) {    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) { diff --git a/clang/lib/AST/StmtSerialization.cpp b/clang/lib/AST/StmtSerialization.cpp index 268922e4813..8faef8bb665 100644 --- a/clang/lib/AST/StmtSerialization.cpp +++ b/clang/lib/AST/StmtSerialization.cpp @@ -227,6 +227,12 @@ Stmt* Stmt::Create(Deserializer& D, ASTContext& C) {      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 @@ CXXZeroInitValueExpr::CreateImpl(Deserializer& D, ASTContext& C) {    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); +} 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); +} diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index ba647cae895..d569994d167 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -238,14 +238,16 @@ public:    //    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 @@ public:                                                 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()) {...}" diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 55616bad762..80b5f200340 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -170,6 +170,200 @@ Sema::ActOnCXXTypeConstructExpr(SourceRange TypeRange, TypeTy *TypeRep,  } +/// 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()) {...}" diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index a622c8afb82..7000c3f5be4 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -250,14 +250,14 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) {  /// 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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {        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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {        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 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S) {          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 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2)    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"); diff --git a/clang/test/SemaCXX/new-delete.cpp b/clang/test/SemaCXX/new-delete.cpp new file mode 100644 index 00000000000..449fcee6489 --- /dev/null +++ b/clang/test/SemaCXX/new-delete.cpp @@ -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}} +}  | 

