[prev in list] [next in list] [prev in thread] [next in thread]
List: cfe-dev
Subject: Re: [cfe-dev] C++ new expression
From: Sebastian Redl <sebastian.redl () getdesigned ! at>
Date: 2008-11-17 22:57:05
Message-ID: 4921F6C1.1080405 () getdesigned ! at
[Download RAW message or body]
Sebastian Redl wrote:
> Sebastian Redl wrote:
>
>> OK, here's my patch for initial parsing, AST and Sema support. There's
>> still some shortcomings, but I'd like to check it in as is, and
>> enhance it later.
>>
> Ignore this patch, it's out of date. I've got a new one, but there's
> still a bug there, and I have a headache so I can't find it now.
>
Ah, finally.
This one is pretty good. Still doesn't have all the checking I want, but
it selects a constructor. For more checking, I'll have to study Doug's
work on names.
Sebastian
["new-delete.patch" (text/plain)]
Index: test/SemaCXX/new-delete.cpp
===================================================================
--- test/SemaCXX/new-delete.cpp (revision 0)
+++ test/SemaCXX/new-delete.cpp (revision 0)
@@ -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}}
+}
Index: include/clang/Basic/DiagnosticKinds.def
===================================================================
--- include/clang/Basic/DiagnosticKinds.def (revision 59467)
+++ include/clang/Basic/DiagnosticKinds.def (working copy)
@@ -1172,6 +1172,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")
Index: include/clang/AST/StmtNodes.def
===================================================================
--- include/clang/AST/StmtNodes.def (revision 59467)
+++ include/clang/AST/StmtNodes.def (working copy)
@@ -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)
Index: include/clang/AST/ExprCXX.h
===================================================================
--- include/clang/AST/ExprCXX.h (revision 59467)
+++ include/clang/AST/ExprCXX.h (working copy)
@@ -433,6 +433,169 @@
// 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 {
+ // 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 : 15;
+ // The number of constructor arguments. This may be 1 even for non-class
+ // types; use the pseudo copy constructor.
+ unsigned NumConstructorArgs : 16;
+ // 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.
+ Decl *OperatorNew;
+ // Points to the deallocation function used in case of error. May be null.
+ Decl *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.
+ Decl *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 initializer,
+ unsigned numPlacementArgs, unsigned numConstructorArgs,
+ Stmt **subExprs, Decl *operatorNew, Decl *operatorDelete,
+ Decl *constructor, SourceLocation startLoc, SourceLocation endLoc)
+ : Expr(CXXNewExprClass, ty), Initializer(initializer),
+ NumPlacementArgs(numPlacementArgs),
+ NumConstructorArgs(numConstructorArgs), SubExprs(subExprs),
+ OperatorNew(operatorNew), OperatorDelete(operatorDelete),
+ Constructor(constructor), AllocType(alloc),
+ StartLoc(startLoc), EndLoc(endLoc)
+ { }
+public:
+ CXXNewExpr(Decl *operatorNew, Expr **placementArgs, unsigned numPlaceArgs,
+ Decl *constructor, bool initializer, Expr **constructorArgs,
+ unsigned numConsArgs, Decl *operatorDelete, QualType ty,
+ QualType alloc, SourceLocation startLoc, SourceLocation endLoc);
+ ~CXXNewExpr() {
+ delete[] SubExprs;
+ }
+
+ QualType getAllocatedType() const { return AllocType; }
+
+ Decl *getOperatorNew() const { return OperatorNew; }
+ Decl *getOperatorDelete() const { return OperatorDelete; }
+ Decl *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 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 the array form of delete, i.e. "delete[]"?
+ bool ArrayForm : 1;
+ // Points to the operator delete overload that is used. Could be a member.
+ Decl *OperatorDelete;
+ // The pointer expression to be deleted.
+ Stmt *Argument;
+ // Location of the expression.
+ SourceLocation Loc;
+public:
+ CXXDeleteExpr(QualType ty, bool arrayForm, Expr *arg, SourceLocation loc)
+ : Expr(CXXDeleteExprClass, ty), ArrayForm(arrayForm), Argument(arg),
+ Loc(loc) { }
+
+ bool isArrayForm() const { return ArrayForm; }
+
+ Decl *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
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h (revision 59467)
+++ include/clang/Parse/Parser.h (working copy)
@@ -515,6 +515,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 ParseNewDirectDeclarator(Declarator &D);
+ ExprResult ParseCXXDeleteExpression();
+
+ //===--------------------------------------------------------------------===//
// C++ if/switch/while/for condition expression.
ExprResult ParseCXXCondition();
@@ -734,7 +742,7 @@
TPResult TryParseBracketDeclarator();
- TypeTy *ParseTypeName();
+ TypeTy *ParseTypeName(bool CXXNewMode = false);
AttributeList *ParseAttributes();
void ParseTypeofSpecifier(DeclSpec &DS);
@@ -760,7 +768,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);
Index: include/clang/Parse/Action.h
===================================================================
--- include/clang/Parse/Action.h (revision 59467)
+++ include/clang/Parse/Action.h (working copy)
@@ -253,8 +253,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;
}
@@ -729,6 +733,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,
+ 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,
Index: Driver/PrintParserCallbacks.cpp
===================================================================
--- Driver/PrintParserCallbacks.cpp (revision 59467)
+++ Driver/PrintParserCallbacks.cpp (working copy)
@@ -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;
}
Index: lib/Sema/SemaExprCXX.cpp
===================================================================
--- lib/Sema/SemaExprCXX.cpp (revision 59467)
+++ lib/Sema/SemaExprCXX.cpp (working copy)
@@ -195,6 +195,196 @@
}
+/// 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,
+ 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.
+ Decl *OperatorNew = 0;
+ Decl *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.
+ Decl *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(OperatorNew, PlaceArgs, NumPlaceArgs, Constructor,
+ Init, ConsArgs, NumConsArgs, OperatorDelete, ResultType,
+ AllocType, 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.
+ 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, ArrayForm, Ex, StartLoc);
+}
+
+
/// ActOnCXXConditionDeclarationExpr - Parsed a condition declaration of a
/// C++ if/switch/while/for statement.
/// e.g: "if (int x = f()) {...}"
Index: lib/Sema/SemaType.cpp
===================================================================
--- lib/Sema/SemaType.cpp (revision 59467)
+++ lib/Sema/SemaType.cpp (working copy)
@@ -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) {
@@ -342,6 +342,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;
@@ -396,9 +398,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
@@ -418,7 +422,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);
@@ -616,12 +622,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");
Index: lib/Sema/Sema.h
===================================================================
--- lib/Sema/Sema.h (revision 59467)
+++ lib/Sema/Sema.h (working copy)
@@ -271,13 +271,15 @@
//
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);
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.
@@ -801,6 +803,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,
+ 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()) {...}"
Index: lib/AST/ExprCXX.cpp
===================================================================
--- lib/AST/ExprCXX.cpp (revision 59467)
+++ lib/AST/ExprCXX.cpp (working copy)
@@ -77,6 +77,38 @@
return child_iterator();
}
+// CXXNewExpr
+CXXNewExpr::CXXNewExpr(Decl *operatorNew, Expr **placementArgs,
+ unsigned numPlaceArgs, Decl *constructor,
+ bool initializer, Expr **constructorArgs,
+ unsigned numConsArgs, Decl *operatorDelete,
+ QualType ty, QualType alloc,
+ SourceLocation startLoc, SourceLocation endLoc)
+ : Expr(CXXNewExprClass, ty), 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
Index: lib/AST/Expr.cpp
===================================================================
--- lib/AST/Expr.cpp (revision 59467)
+++ lib/AST/Expr.cpp (working copy)
@@ -326,7 +326,13 @@
case CXXDefaultArgExprClass:
return cast<CXXDefaultArgExpr>(this)->getExpr()->hasLocalSideEffect();
- }
+
+ case CXXNewExprClass:
+ // In theory, there might be new expressions that don't have side effects
+ // (e.g. a placement new with an uninitialized POD), but those are obscure.
+ case CXXDeleteExprClass:
+ return true;
+ }
}
/// DeclCanBeLvalue - Determine whether the given declaration can be
@@ -468,8 +474,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;
}
Index: lib/AST/StmtSerialization.cpp
===================================================================
--- lib/AST/StmtSerialization.cpp (revision 59467)
+++ lib/AST/StmtSerialization.cpp (working copy)
@@ -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,60 @@
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);
+ // FIXME: What about the default allocation functions? We don't want to
+ // own them to avoid the mess DeclRefExpr is in, but who would?
+ 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 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);
+ Decl *OperatorNew = D.ReadPtr<Decl>();
+ Decl *OperatorDelete = D.ReadPtr<Decl>();
+ Decl *Constructor = D.ReadPtr<Decl>();
+ QualType AllocType = QualType::ReadVal(D);
+ SourceLocation StartLoc = SourceLocation::ReadVal(D);
+ SourceLocation EndLoc = SourceLocation::ReadVal(D);
+
+ return new CXXNewExpr(T, AllocType, Initializer, NumPlacementArgs,
+ NumConstructorArgs, SubExprs, OperatorNew,
+ OperatorDelete, Constructor, StartLoc, EndLoc);
+}
+
+void CXXDeleteExpr::EmitImpl(Serializer& S) const {
+ S.Emit(getType());
+ S.Emit(ArrayForm);
+ S.EmitOwnedPtr(Argument);
+ S.Emit(Loc);
+}
+
+CXXDeleteExpr *
+CXXDeleteExpr::CreateImpl(Deserializer& D, ASTContext& C) {
+ QualType Ty = QualType::ReadVal(D);
+ bool ArrayForm = D.ReadBool();
+ Stmt *Argument = D.ReadOwnedPtr<Stmt>(C);
+ SourceLocation Loc = SourceLocation::ReadVal(D);
+ return new CXXDeleteExpr(Ty, ArrayForm, cast<Expr>(Argument), Loc);
+}
Index: lib/AST/StmtPrinter.cpp
===================================================================
--- lib/AST/StmtPrinter.cpp (revision 59467)
+++ lib/AST/StmtPrinter.cpp (working copy)
@@ -925,6 +925,45 @@
PrintRawDecl(E->getVarDecl());
}
+void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
+ // FIXME: How to recover the '::'?
+ 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 << ") ";
+ }
+ // FIXME: We lose the info about whether it was a new-type-id or a (type-id)
+ // Depending on the situation, this can lead to invalid code.
+ OS << E->getAllocatedType().getAsString();
+
+ 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) {
+ // FIXME: How to recover the '::'?
+ OS << "delete ";
+ if (E->isArrayForm())
+ OS << "[] ";
+ PrintExpr(E->getArgument());
+}
+
// Obj-C
void StmtPrinter::VisitObjCStringLiteral(ObjCStringLiteral *Node) {
Index: lib/Parse/ParseDecl.cpp
===================================================================
--- lib/Parse/ParseDecl.cpp (revision 59467)
+++ lib/Parse/ParseDecl.cpp (working copy)
@@ -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,
@@ -1368,7 +1373,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.
@@ -1377,7 +1382,7 @@
Diag(InnerChunk.Loc, diag::err_illegal_decl_reference_to_reference,
D.getIdentifier() ? D.getIdentifier()->getName() : "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.
}
@@ -1583,7 +1588,7 @@
if (AttrList)
D.AddAttributes(AttrList);
- ParseDeclaratorInternal(D);
+ ParseDeclaratorInternal(D, &Parser::ParseDirectDeclarator);
// Match the ')'.
MatchRHSPunctuation(tok::r_paren, StartLoc);
Index: lib/Parse/ParseExpr.cpp
===================================================================
--- lib/Parse/ParseExpr.cpp (revision 59467)
+++ lib/Parse/ParseExpr.cpp (working copy)
@@ -350,6 +350,8 @@
/// [GNU] '__alignof' '(' type-name ')'
/// [C++0x] 'alignof' '(' type-id ')'
/// [GNU] '&&' identifier
+/// [C++] new-expression
+/// [C++] delete-expression
///
/// unary-operator: one of
/// '&' '*' '+' '-' '~' '!'
@@ -404,6 +406,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.
@@ -613,6 +625,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);
Index: lib/Parse/ParseExprCXX.cpp
===================================================================
--- lib/Parse/ParseExprCXX.cpp (revision 59467)
+++ lib/Parse/ParseExprCXX.cpp (working copy)
@@ -618,7 +618,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);
@@ -627,3 +627,221 @@
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;
+ 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();
+ } else {
+ // We still need the type.
+ if (Tok.is(tok::l_paren)) {
+ ConsumeParen();
+ TyStart = Tok.getLocation();
+ Ty = ParseTypeName(/*CXXNewMode=*/true);
+ } else {
+ TyStart = Tok.getLocation();
+ Ty = ParseNewTypeId();
+ }
+ if (!Ty)
+ return true;
+ TyEnd = Tok.getLocation();
+ }
+ } else {
+ TyStart = Tok.getLocation();
+ Ty = ParseNewTypeId();
+ if (!Ty)
+ return true;
+ TyEnd = Tok.getLocation();
+ }
+
+ 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, 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
+///
+/// direct-new-declarator:
+/// '[' expression ']'
+/// direct-new-declarator '[' constant-expression ']'
+///
+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 new-direct-declarator.
+ Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
+ ParseDeclaratorInternal(DeclaratorInfo, &Parser::ParseNewDirectDeclarator);
+
+ TypeTy *Ty = Actions.ActOnTypeName(CurScope, DeclaratorInfo,
+ /*CXXNewMode=*/true).Val;
+ return DeclaratorInfo.getInvalidType() ? 0 : Ty;
+}
+
+void Parser::ParseNewDirectDeclarator(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 alrady 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);
+}
_______________________________________________
cfe-dev mailing list
cfe-dev@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-dev
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic