diff options
-rw-r--r-- | Driver/PrintParserCallbacks.cpp | 2 | ||||
-rw-r--r-- | include/clang/AST/ExprCXX.h | 180 | ||||
-rw-r--r-- | include/clang/AST/StmtNodes.def | 2 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticKinds.def | 14 | ||||
-rw-r--r-- | include/clang/Parse/Action.h | 38 | ||||
-rw-r--r-- | include/clang/Parse/Parser.h | 15 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 10 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 33 | ||||
-rw-r--r-- | lib/AST/StmtPrinter.cpp | 43 | ||||
-rw-r--r-- | lib/AST/StmtSerialization.cpp | 69 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 31 | ||||
-rw-r--r-- | lib/Parse/ParseExpr.cpp | 19 | ||||
-rw-r--r-- | lib/Parse/ParseExprCXX.cpp | 228 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 23 | ||||
-rw-r--r-- | lib/Sema/SemaExprCXX.cpp | 194 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 18 | ||||
-rw-r--r-- | test/SemaCXX/new-delete.cpp | 56 |
17 files changed, 945 insertions, 30 deletions
diff --git a/Driver/PrintParserCallbacks.cpp b/Driver/PrintParserCallbacks.cpp index 2ee113fcda..02203d356d 100644 --- a/Driver/PrintParserCallbacks.cpp +++ b/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/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index c855089d8f..201a9331db 100644 --- a/include/clang/AST/ExprCXX.h +++ b/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/include/clang/AST/StmtNodes.def b/include/clang/AST/StmtNodes.def index beb64c51f3..6d3c172c96 100644 --- a/include/clang/AST/StmtNodes.def +++ b/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/include/clang/Basic/DiagnosticKinds.def b/include/clang/Basic/DiagnosticKinds.def index 6a85df0e18..4525355ba3 100644 --- a/include/clang/Basic/DiagnosticKinds.def +++ b/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/include/clang/Parse/Action.h b/include/clang/Parse/Action.h index d00fbd3361..9a7b41b9e5 100644 --- a/include/clang/Parse/Action.h +++ b/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/include/clang/Parse/Parser.h b/include/clang/Parse/Parser.h index 0c061219f8..76edfc1414 100644 --- a/include/clang/Parse/Parser.h +++ b/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/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 2e13352a5a..e6a7b4114a 100644 --- a/lib/AST/Expr.cpp +++ b/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/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 1155a4b9c6..c0f2985f1e 100644 --- a/lib/AST/ExprCXX.cpp +++ b/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/lib/AST/StmtPrinter.cpp b/lib/AST/StmtPrinter.cpp index cf6d4c0b90..cb5c44f926 100644 --- a/lib/AST/StmtPrinter.cpp +++ b/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/lib/AST/StmtSerialization.cpp b/lib/AST/StmtSerialization.cpp index 268922e481..8faef8bb66 100644 --- a/lib/AST/StmtSerialization.cpp +++ b/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/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 92a5fdb929..3262c0de1c 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/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/lib/Parse/ParseExpr.cpp b/lib/Parse/ParseExpr.cpp index 74b0715de2..9f9b306c45 100644 --- a/lib/Parse/ParseExpr.cpp +++ b/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/lib/Parse/ParseExprCXX.cpp b/lib/Parse/ParseExprCXX.cpp index 46c7a135e0..9eb2431642 100644 --- a/lib/Parse/ParseExprCXX.cpp +++ b/lib/Parse/ParseExprCXX.cpp @@ -614,7 +614,7 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() { // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. Declarator D(DS, Declarator::TypeNameContext); - ParseDeclaratorInternal(D, /*PtrOperator=*/true); + ParseDeclaratorInternal(D, /*DirectDeclParser=*/0); // Finish up the type. Action::TypeResult Result = Actions.ActOnTypeName(CurScope, D); @@ -623,3 +623,229 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() { else return Result.Val; } + +/// ParseCXXNewExpression - Parse a C++ new-expression. New is used to allocate +/// memory in a typesafe manner and call constructors. +/// +/// new-expression: +/// '::'[opt] 'new' new-placement[opt] new-type-id +/// new-initializer[opt] +/// '::'[opt] 'new' new-placement[opt] '(' type-id ')' +/// new-initializer[opt] +/// +/// new-placement: +/// '(' expression-list ')' +/// +/// new-initializer: +/// '(' expression-list[opt] ')' +/// [C++0x] braced-init-list [TODO] +/// +Parser::ExprResult Parser::ParseCXXNewExpression() +{ + assert((Tok.is(tok::coloncolon) || Tok.is(tok::kw_new)) && + "Expected :: or 'new' keyword"); + + SourceLocation Start = Tok.getLocation(); + bool UseGlobal = false; + if (Tok.is(tok::coloncolon)) { + UseGlobal = true; + ConsumeToken(); + } + + assert(Tok.is(tok::kw_new) && "Lookahead should have ensured 'new'"); + // Consume 'new' + ConsumeToken(); + + // A '(' now can be a new-placement or the '(' wrapping the type-id in the + // second form of new-expression. It can't be a new-type-id. + + ExprListTy PlacementArgs; + SourceLocation PlacementLParen, PlacementRParen; + + TypeTy *Ty = 0; + SourceLocation TyStart, TyEnd; + bool ParenTypeId; + if (Tok.is(tok::l_paren)) { + // If it turns out to be a placement, we change the type location. + PlacementLParen = ConsumeParen(); + TyStart = Tok.getLocation(); + if (ParseExpressionListOrTypeId(PlacementArgs, Ty)) + return true; + TyEnd = Tok.getLocation(); + + PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen); + if (PlacementRParen.isInvalid()) + return true; + + if (Ty) { + // Reset the placement locations. There was no placement. + PlacementLParen = PlacementRParen = SourceLocation(); + ParenTypeId = true; + } else { + // We still need the type. + if (Tok.is(tok::l_paren)) { + ConsumeParen(); + TyStart = Tok.getLocation(); + Ty = ParseTypeName(/*CXXNewMode=*/true); + ParenTypeId = true; + } else { + TyStart = Tok.getLocation(); + Ty = ParseNewTypeId(); + ParenTypeId = false; + } + if (!Ty) + return true; + TyEnd = Tok.getLocation(); + } + } else { + TyStart = Tok.getLocation(); + Ty = ParseNewTypeId(); + if (!Ty) + return true; + TyEnd = Tok.getLocation(); + ParenTypeId = false; + } + + ExprListTy ConstructorArgs; + SourceLocation ConstructorLParen, ConstructorRParen; + + if (Tok.is(tok::l_paren)) { + ConstructorLParen = ConsumeParen(); + if (Tok.isNot(tok::r_paren)) { + CommaLocsTy CommaLocs; + if (ParseExpressionList(ConstructorArgs, CommaLocs)) + return true; + } + ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen); + if (ConstructorRParen.isInvalid()) + return true; + } + + return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen, + &PlacementArgs[0], PlacementArgs.size(), + PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd, + ConstructorLParen, &ConstructorArgs[0], + ConstructorArgs.size(), ConstructorRParen); +} + +/// ParseNewTypeId - Parses a type ID as it appears in a new expression. +/// The most interesting part of this is the new-declarator, which can be a +/// multi-dimensional array, of which the first has a non-constant expression as +/// the size, e.g. +/// @code new int[runtimeSize()][2][2] @endcode +/// +/// new-type-id: +/// type-specifier-seq new-declarator[opt] +/// +/// new-declarator: +/// ptr-operator new-declarator[opt] +/// direct-new-declarator +/// +Parser::TypeTy * Parser::ParseNewTypeId() +{ + DeclSpec DS; + if (ParseCXXTypeSpecifierSeq(DS)) + return 0; + + // A new-declarator is a simplified version of a declarator. We use + // ParseDeclaratorInternal, but pass our own direct declarator parser, + // one that parses a direct-new-declarator. + Declarator DeclaratorInfo(DS, Declarator::Type |