forked from OSchip/llvm-project
Implementation of new and delete parsing and sema.
This version uses VLAs to represent arrays. I'll try an alternative way next, but I want this safe first. llvm-svn: 59835
This commit is contained in:
parent
8dfa51c5ef
commit
bd150f431e
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -508,6 +508,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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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()) {...}"
|
||||
|
|
|
@ -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()) {...}"
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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}}
|
||||
}
|
Loading…
Reference in New Issue