Handle new by passing the Declaration to the Action, not a processed type.

llvm-svn: 60413
This commit is contained in:
Sebastian Redl
2008-12-02 14:43:59 +00:00
parent 318ccb0e62
commit 351bb78a10
15 changed files with 228 additions and 187 deletions

View File

@@ -168,7 +168,7 @@ namespace {
// Type Parsing Callbacks.
//===--------------------------------------------------------------------===//
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
llvm::cout << __FUNCTION__ << "\n";
return 0;
}

View File

@@ -445,13 +445,16 @@ class CXXNewExpr : public Expr {
// Is there an initializer? If not, built-ins are uninitialized, else they're
// value-initialized.
bool Initializer : 1;
// Do we allocate an array? If so, the first SubExpr is the size expression.
bool Array : 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.
unsigned NumConstructorArgs : 14;
// Contains an optional array size expression, 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;
@@ -461,29 +464,25 @@ class CXXNewExpr : public Expr {
// 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)
CXXNewExpr(QualType ty, bool globalNew, bool parenTypeId, bool initializer,
bool array, unsigned numPlaceArgs, unsigned numConsArgs,
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),
Initializer(initializer), Array(array), NumPlacementArgs(numPlaceArgs),
NumConstructorArgs(numConsArgs), SubExprs(subExprs),
OperatorNew(operatorNew), OperatorDelete(operatorDelete),
Constructor(constructor), AllocType(alloc),
StartLoc(startLoc), EndLoc(endLoc)
Constructor(constructor), StartLoc(startLoc), EndLoc(endLoc)
{ }
public:
CXXNewExpr(bool globalNew, FunctionDecl *operatorNew, Expr **placementArgs,
unsigned numPlaceArgs, bool ParenTypeId, QualType alloc,
unsigned numPlaceArgs, bool ParenTypeId, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
FunctionDecl *operatorDelete, QualType ty,
@@ -492,20 +491,31 @@ public:
delete[] SubExprs;
}
QualType getAllocatedType() const { return AllocType; }
QualType getAllocatedType() const {
assert(getType()->isPointerType());
return getType()->getAsPointerType()->getPointeeType();
}
FunctionDecl *getOperatorNew() const { return OperatorNew; }
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
CXXConstructorDecl *getConstructor() const { return Constructor; }
bool isArray() const { return Array; }
Expr *getArraySize() {
return Array ? cast<Expr>(SubExprs[0]) : 0;
}
const Expr *getArraySize() const {
return Array ? cast<Expr>(SubExprs[0]) : 0;
}
unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
Expr *getPlacementArg(unsigned i) {
assert(i < NumPlacementArgs && "Index out of range");
return cast<Expr>(SubExprs[i]);
return cast<Expr>(SubExprs[Array + i]);
}
const Expr *getPlacementArg(unsigned i) const {
assert(i < NumPlacementArgs && "Index out of range");
return cast<Expr>(SubExprs[i]);
return cast<Expr>(SubExprs[Array + i]);
}
bool isGlobalNew() const { return GlobalNew; }
@@ -515,40 +525,40 @@ public:
unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
Expr *getConstructorArg(unsigned i) {
assert(i < NumConstructorArgs && "Index out of range");
return cast<Expr>(SubExprs[NumPlacementArgs + i]);
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
}
const Expr *getConstructorArg(unsigned i) const {
assert(i < NumConstructorArgs && "Index out of range");
return cast<Expr>(SubExprs[NumPlacementArgs + i]);
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
}
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
arg_iterator placement_arg_begin() {
return SubExprs;
return SubExprs + Array;
}
arg_iterator placement_arg_end() {
return SubExprs + getNumPlacementArgs();
return SubExprs + Array + getNumPlacementArgs();
}
const_arg_iterator placement_arg_begin() const {
return SubExprs;
return SubExprs + Array;
}
const_arg_iterator placement_arg_end() const {
return SubExprs + getNumPlacementArgs();
return SubExprs + Array + getNumPlacementArgs();
}
arg_iterator constructor_arg_begin() {
return SubExprs + getNumPlacementArgs();
return SubExprs + Array + getNumPlacementArgs();
}
arg_iterator constructor_arg_end() {
return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
}
const_arg_iterator constructor_arg_begin() const {
return SubExprs + getNumPlacementArgs();
return SubExprs + Array + getNumPlacementArgs();
}
const_arg_iterator constructor_arg_end() const {
return SubExprs + getNumPlacementArgs() + getNumConstructorArgs();
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
}
virtual SourceRange getSourceRange() const {

View File

@@ -1228,15 +1228,16 @@ 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")
// FIXME: merge with %select
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_static_illegal_in_new, ERROR,
"the 'static' modifier for the array size is not legal in new expressions")
DIAG(err_array_new_needs_size, ERROR,
"array size must be specified in new expressions")
DIAG(err_bad_new_type, ERROR,
"cannot allocate %select{function|incomplete|reference}1 type %0 with new")
DIAG(err_new_array_nonconst, ERROR,
"only the first dimension of an allocated array may be non-const")
DIAG(err_array_size_not_integral, ERROR,
"array size expression must have integral or enumerated type, not %0")
DIAG(err_new_uninitialized_const, ERROR,
"must provide an initializer if the allocated object is 'const'")
DIAG(err_delete_operand, ERROR,

View File

@@ -258,10 +258,7 @@ public:
//===--------------------------------------------------------------------===//
/// 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) {
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D) {
return 0;
}
@@ -760,18 +757,12 @@ public:
/// 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]".
/// expressions in ConstructorArgs. The type is passed as a declarator.
virtual ExprResult ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
ExprTy **PlacementArgs, unsigned NumPlaceArgs,
SourceLocation PlacementRParen,
bool ParenTypeId, SourceLocation TyStart,
TypeTy *Ty, SourceLocation TyEnd,
bool ParenTypeId, Declarator &D,
SourceLocation ConstructorLParen,
ExprTy **ConstructorArgs, unsigned NumConsArgs,
SourceLocation ConstructorRParen) {

View File

@@ -509,8 +509,7 @@ private:
//===--------------------------------------------------------------------===//
// C++ 5.3.4 and 5.3.5: C++ new and delete
ExprResult ParseCXXNewExpression();
TypeTy *ParseNewTypeId();
bool ParseExpressionListOrTypeId(ExprListTy &Exprs, TypeTy *&Ty);
bool ParseExpressionListOrTypeId(ExprListTy &Exprs, Declarator &D);
void ParseDirectNewDeclarator(Declarator &D);
ExprResult ParseCXXDeleteExpression();
@@ -736,7 +735,7 @@ private:
TPResult TryParseBracketDeclarator();
TypeTy *ParseTypeName(bool CXXNewMode = false);
TypeTy *ParseTypeName();
AttributeList *ParseAttributes();
void ParseTypeofSpecifier(DeclSpec &DS);

View File

@@ -80,30 +80,32 @@ Stmt::child_iterator CXXConditionDeclExpr::child_end() {
// CXXNewExpr
CXXNewExpr::CXXNewExpr(bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
bool parenTypeId, QualType alloc,
bool parenTypeId, Expr *arraySize,
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),
Initializer(initializer), Array(arraySize), NumPlacementArgs(numPlaceArgs),
NumConstructorArgs(numConsArgs), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor), AllocType(alloc),
OperatorDelete(operatorDelete), Constructor(constructor),
StartLoc(startLoc), EndLoc(endLoc)
{
unsigned TotalSize = NumPlacementArgs + NumConstructorArgs;
unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
SubExprs = new Stmt*[TotalSize];
unsigned i = 0;
for(unsigned j = 0; j < NumPlacementArgs; ++j)
if (Array)
SubExprs[i++] = arraySize;
for (unsigned j = 0; j < NumPlacementArgs; ++j)
SubExprs[i++] = placementArgs[j];
for(unsigned j = 0; j < NumConstructorArgs; ++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();
return &SubExprs[0] + Array + getNumPlacementArgs() + getNumConstructorArgs();
}
// CXXDeleteExpr

View File

@@ -953,6 +953,9 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
}
if (E->isParenTypeId())
OS << "(";
// FIXME: This doesn't print the dynamic array size. We'd have to split up
// the allocated type to correctly emit that, but without an ASTContext,
// that's not possible.
OS << E->getAllocatedType().getAsString();
if (E->isParenTypeId())
OS << ")";

View File

@@ -1444,7 +1444,10 @@ CXXZeroInitValueExpr::CreateImpl(Deserializer& D, ASTContext& C) {
void CXXNewExpr::EmitImpl(Serializer& S) const {
S.Emit(getType());
S.Emit(Initializer);
S.EmitBool(GlobalNew);
S.EmitBool(ParenTypeId);
S.EmitBool(Initializer);
S.EmitBool(Array);
S.EmitInt(NumPlacementArgs);
S.EmitInt(NumConstructorArgs);
S.BatchEmitOwnedPtrs(NumPlacementArgs + NumConstructorArgs, SubExprs);
@@ -1455,7 +1458,6 @@ void CXXNewExpr::EmitImpl(Serializer& S) const {
S.EmitPtr(OperatorNew);
S.EmitPtr(OperatorDelete);
S.EmitPtr(Constructor);
S.Emit(AllocType);
S.Emit(StartLoc);
S.Emit(EndLoc);
}
@@ -1466,19 +1468,19 @@ CXXNewExpr::CreateImpl(Deserializer& D, ASTContext& C) {
bool GlobalNew = D.ReadBool();
bool ParenTypeId = D.ReadBool();
bool Initializer = D.ReadBool();
bool Array = D.ReadBool();
unsigned NumPlacementArgs = D.ReadInt();
unsigned NumConstructorArgs = D.ReadInt();
unsigned TotalExprs = NumPlacementArgs + NumConstructorArgs;
unsigned TotalExprs = Array + 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,
return new CXXNewExpr(T, GlobalNew, ParenTypeId, Initializer, Array,
NumPlacementArgs, NumConstructorArgs, SubExprs,
OperatorNew, OperatorDelete, Constructor, StartLoc,
EndLoc);
@@ -1486,8 +1488,8 @@ CXXNewExpr::CreateImpl(Deserializer& D, ASTContext& C) {
void CXXDeleteExpr::EmitImpl(Serializer& S) const {
S.Emit(getType());
S.Emit(GlobalDelete);
S.Emit(ArrayForm);
S.EmitBool(GlobalDelete);
S.EmitBool(ArrayForm);
S.EmitPtr(OperatorDelete);
S.EmitOwnedPtr(Argument);
S.Emit(Loc);

View File

@@ -28,9 +28,7 @@ using namespace clang;
/// specifier-qualifier-list abstract-declarator[opt]
///
/// 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) {
Parser::TypeTy *Parser::ParseTypeName() {
// Parse the common declaration-specifiers piece.
DeclSpec DS;
ParseSpecifierQualifierList(DS);
@@ -39,7 +37,7 @@ Parser::TypeTy *Parser::ParseTypeName(bool CXXNewMode) {
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
ParseDeclarator(DeclaratorInfo);
return Actions.ActOnTypeName(CurScope, DeclaratorInfo, CXXNewMode).Val;
return Actions.ActOnTypeName(CurScope, DeclaratorInfo).Val;
}
/// ParseAttributes - Parse a non-empty attributes list.

View File

@@ -645,6 +645,13 @@ Parser::TypeTy *Parser::ParseConversionFunctionId() {
/// new-placement:
/// '(' expression-list ')'
///
/// new-type-id:
/// type-specifier-seq new-declarator[opt]
///
/// new-declarator:
/// ptr-operator new-declarator[opt]
/// direct-new-declarator
///
/// new-initializer:
/// '(' expression-list[opt] ')'
/// [C++0x] braced-init-list [TODO]
@@ -671,49 +678,58 @@ Parser::ExprResult Parser::ParseCXXNewExpression()
ExprVector PlacementArgs(Actions);
SourceLocation PlacementLParen, PlacementRParen;
TypeTy *Ty = 0;
SourceLocation TyStart, TyEnd;
bool ParenTypeId;
DeclSpec DS;
Declarator DeclaratorInfo(DS, Declarator::TypeNameContext);
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))
if (ParseExpressionListOrTypeId(PlacementArgs, DeclaratorInfo)) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return true;
TyEnd = Tok.getLocation();
}
PlacementRParen = MatchRHSPunctuation(tok::r_paren, PlacementLParen);
if (PlacementRParen.isInvalid())
if (PlacementRParen.isInvalid()) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return true;
}
if (Ty) {
if (PlacementArgs.empty()) {
// 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);
SourceLocation LParen = ConsumeParen();
ParseSpecifierQualifierList(DS);
ParseDeclarator(DeclaratorInfo);
MatchRHSPunctuation(tok::r_paren, LParen);
ParenTypeId = true;
} else {
TyStart = Tok.getLocation();
Ty = ParseNewTypeId();
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
ParenTypeId = false;
}
if (!Ty)
return true;
TyEnd = Tok.getLocation();
}
} else {
TyStart = Tok.getLocation();
Ty = ParseNewTypeId();
if (!Ty)
return true;
TyEnd = Tok.getLocation();
// A new-type-id is a simplified type-id, where essentially the
// direct-declarator is replaced by a direct-new-declarator.
if (ParseCXXTypeSpecifierSeq(DS))
DeclaratorInfo.setInvalidType(true);
else
ParseDeclaratorInternal(DeclaratorInfo,
&Parser::ParseDirectNewDeclarator);
ParenTypeId = false;
}
if (DeclaratorInfo.getInvalidType()) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return true;
}
ExprVector ConstructorArgs(Actions);
SourceLocation ConstructorLParen, ConstructorRParen;
@@ -722,51 +738,25 @@ Parser::ExprResult Parser::ParseCXXNewExpression()
ConstructorLParen = ConsumeParen();
if (Tok.isNot(tok::r_paren)) {
CommaLocsTy CommaLocs;
if (ParseExpressionList(ConstructorArgs, CommaLocs))
if (ParseExpressionList(ConstructorArgs, CommaLocs)) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return true;
}
}
ConstructorRParen = MatchRHSPunctuation(tok::r_paren, ConstructorLParen);
if (ConstructorRParen.isInvalid())
if (ConstructorRParen.isInvalid()) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return true;
}
}
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
PlacementArgs.take(), PlacementArgs.size(),
PlacementRParen, ParenTypeId, TyStart, Ty, TyEnd,
PlacementRParen, ParenTypeId, DeclaratorInfo,
ConstructorLParen, ConstructorArgs.take(),
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.
///
@@ -806,12 +796,14 @@ void Parser::ParseDirectNewDeclarator(Declarator &D)
/// new-placement:
/// '(' expression-list ')'
///
bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs, TypeTy *&Ty)
bool Parser::ParseExpressionListOrTypeId(ExprListTy &PlacementArgs,
Declarator &D)
{
// The '(' was already consumed.
if (isTypeIdInParens()) {
Ty = ParseTypeName(/*CXXNewMode=*/true);
return Ty == 0;
ParseSpecifierQualifierList(D.getMutableDeclSpec());
ParseDeclarator(D);
return D.getInvalidType();
}
// It's not a type, it has to be an expression list.

View File

@@ -245,16 +245,14 @@ public:
//
QualType ConvertDeclSpecToType(const DeclSpec &DS);
void ProcessTypeAttributeList(QualType &Result, const AttributeList *AL);
QualType GetTypeForDeclarator(Declarator &D, Scope *S,
bool CXXNewMode = false);
QualType GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip = 0);
DeclarationName GetNameForDeclarator(Declarator &D);
QualType ObjCGetTypeForMethodDefinition(DeclTy *D);
bool UnwrapSimilarPointerTypes(QualType& T1, QualType& T2);
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D,
bool CXXNewMode = false);
virtual TypeResult ActOnTypeName(Scope *S, Declarator &D);
//===--------------------------------------------------------------------===//
// Symbol table / Decl tracking callbacks: SemaDecl.cpp.
@@ -828,13 +826,11 @@ public:
SourceLocation PlacementLParen,
ExprTy **PlacementArgs, unsigned NumPlaceArgs,
SourceLocation PlacementRParen,
bool ParenTypeId, SourceLocation TyStart,
TypeTy *Ty, SourceLocation TyEnd,
bool ParenTypeId, Declarator &D,
SourceLocation ConstructorLParen,
ExprTy **ConstructorArgs, unsigned NumConsArgs,
SourceLocation ConstructorRParen);
bool CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
const SourceRange &TyR);
bool CheckAllocatedType(QualType AllocType, const Declarator &D);
/// ActOnCXXDelete - Parsed a C++ 'delete' expression
virtual ExprResult ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,

View File

@@ -180,30 +180,60 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
ExprTy **PlacementArgs, unsigned NumPlaceArgs,
SourceLocation PlacementRParen, bool ParenTypeId,
SourceLocation TyStart, TypeTy *Ty, SourceLocation TyEnd,
SourceLocation ConstructorLParen,
Declarator &D, 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();
// FIXME: Throughout this function, we have rather bad location information.
// Implementing Declarator::getSourceRange() would go a long way toward
// fixing that.
// Validate the type, and unwrap an array if any.
if (CheckAllocatedType(CheckType, StartLoc, SourceRange(TyStart, TyEnd)))
Expr *ArraySize = 0;
unsigned Skip = 0;
// If the specified type is an array, unwrap it and save the expression.
if (D.getNumTypeObjects() > 0 &&
D.getTypeObject(0).Kind == DeclaratorChunk::Array) {
DeclaratorChunk &Chunk = D.getTypeObject(0);
if (Chunk.Arr.hasStatic)
return Diag(Chunk.Loc, diag::err_static_illegal_in_new);
if (!Chunk.Arr.NumElts)
return Diag(Chunk.Loc, diag::err_array_new_needs_size);
ArraySize = static_cast<Expr*>(Chunk.Arr.NumElts);
Skip = 1;
}
QualType AllocType = GetTypeForDeclarator(D, /*Scope=*/0, Skip);
if (D.getInvalidType())
return true;
QualType ResultType = Context.getPointerType(CheckType);
if (CheckAllocatedType(AllocType, D))
return true;
QualType ResultType = Context.getPointerType(AllocType);
// 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.
if (ArraySize) {
QualType SizeType = ArraySize->getType();
if (!SizeType->isIntegralType() && !SizeType->isEnumeralType())
return Diag(ArraySize->getSourceRange().getBegin(),
diag::err_array_size_not_integral)
<< SizeType << ArraySize->getSourceRange();
// Let's see if this is a constant < 0. If so, we reject it out of hand.
// We don't care about special rules, so we tell the machinery it's not
// evaluated - it gives us a result in more cases.
llvm::APSInt Value;
if (ArraySize->isIntegerConstantExpr(Value, Context, 0, false)) {
if (Value < llvm::APSInt(
llvm::APInt::getNullValue(Value.getBitWidth()), false))
return Diag(ArraySize->getSourceRange().getBegin(),
diag::err_typecheck_negative_array_size)
<< ArraySize->getSourceRange();
}
}
// --- Choosing an allocation function ---
// C++ 5.3.4p8 - 14 & 18
@@ -239,12 +269,14 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
// 2) Otherwise, the object is direct-initialized.
CXXConstructorDecl *Constructor = 0;
Expr **ConsArgs = (Expr**)ConstructorArgs;
if (const RecordType *RT = CheckType->getAsRecordType()) {
if (const RecordType *RT = AllocType->getAsRecordType()) {
// 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),
AllocType, ConsArgs, NumConsArgs,
D.getDeclSpec().getSourceRange().getBegin(),
SourceRange(D.getDeclSpec().getSourceRange().getBegin(),
ConstructorRParen),
RT->getDecl()->getDeclName(),
NumConsArgs != 0 ? IK_Direct : IK_Default);
if (!Constructor)
@@ -252,9 +284,9 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
} else {
if (!Init) {
// FIXME: Check that no subpart is const.
if (CheckType.isConstQualified()) {
if (AllocType.isConstQualified()) {
Diag(StartLoc, diag::err_new_uninitialized_const)
<< SourceRange(StartLoc, TyEnd);
<< D.getSourceRange();
return true;
}
} else if (NumConsArgs == 0) {
@@ -262,8 +294,8 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
} else if (NumConsArgs == 1) {
// Object is direct-initialized.
// FIXME: WHAT DeclarationName do we pass in here?
if (CheckInitializerTypes(ConsArgs[0], CheckType, StartLoc,
DeclarationName() /*CheckType.getAsString()*/))
if (CheckInitializerTypes(ConsArgs[0], AllocType, StartLoc,
DeclarationName() /*AllocType.getAsString()*/))
return true;
} else {
Diag(StartLoc, diag::err_builtin_direct_init_more_than_one_arg)
@@ -274,16 +306,15 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
// FIXME: Also check that the destructor is accessible. (C++ 5.3.4p16)
return new CXXNewExpr(UseGlobal, OperatorNew, PlaceArgs, NumPlaceArgs,
ParenTypeId, AllocType, Constructor, Init,
ParenTypeId, ArraySize, Constructor, Init,
ConsArgs, NumConsArgs, OperatorDelete, ResultType,
StartLoc, Init ? ConstructorRParen : TyEnd);
StartLoc, Init ? ConstructorRParen : SourceLocation());
}
/// 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)
bool Sema::CheckAllocatedType(QualType AllocType, const Declarator &D)
{
// C++ 5.3.4p1: "[The] type shall be a complete object type, but not an
// abstract class type or array thereof.
@@ -291,29 +322,34 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation StartLoc,
// 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;
unsigned type; // For the select in the message.
if (AllocType->isFunctionType()) {
msg = diag::err_new_function;
type = 0;
} else if(AllocType->isIncompleteType()) {
msg = diag::err_new_incomplete;
} else if(AllocType->isReferenceType()) {
msg = diag::err_new_reference;
type = 1;
} else {
assert(false && "Unexpected type class");
return true;
assert(AllocType->isReferenceType() && "What else could it be?");
type = 2;
}
Diag(StartLoc, msg) << AllocType << TyR;
SourceRange TyR = D.getDeclSpec().getSourceRange();
// FIXME: This is very much a guess and won't work for, e.g., pointers.
if (D.getNumTypeObjects() > 0)
TyR.setEnd(D.getTypeObject(0).Loc);
Diag(TyR.getBegin(), diag::err_bad_new_type)
<< AllocType.getAsString() << type << TyR;
return true;
}
// Every dimension beyond the first shall be of constant size.
// Every dimension shall be of constant size.
unsigned i = 1;
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;
Diag(D.getTypeObject(i).Loc, diag::err_new_array_nonconst)
<< static_cast<Expr*>(D.getTypeObject(i).Arr.NumElts)->getSourceRange();
return true;
}
AllocType = Array->getElementType();
++i;
}
return false;

View File

@@ -249,8 +249,8 @@ QualType Sema::ConvertDeclSpecToType(const DeclSpec &DS) {
}
/// GetTypeForDeclarator - Convert the type for the specified declarator to Type
/// instances.
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
/// instances. Skip the outermost Skip type objects.
QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, unsigned Skip) {
// long long is a C99 feature.
if (!getLangOptions().C99 && !getLangOptions().CPlusPlus0x &&
D.getDeclSpec().getTypeSpecWidth() == DeclSpec::TSW_longlong)
@@ -260,8 +260,8 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
// 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) {
DeclaratorChunk &DeclType = D.getTypeObject(e-i-1);
for (unsigned i = Skip, e = D.getNumTypeObjects(); i != e; ++i) {
DeclaratorChunk &DeclType = D.getTypeObject(e-i-1+Skip);
switch (DeclType.Kind) {
default: assert(0 && "Unknown decltype!");
case DeclaratorChunk::BlockPointer:
@@ -340,8 +340,6 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
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,11 +392,9 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
if (!ArraySize) {
T = Context.getIncompleteArrayType(T, ASM, ATI.TypeQuals);
} else if (!ArraySize->isIntegerConstantExpr(ConstVal, Context) ||
!T->isConstantSizeType() || UseCXXNewMode) {
!T->isConstantSizeType()) {
// 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,9 +414,7 @@ QualType Sema::GetTypeForDeclarator(Declarator &D, Scope *S, bool CXXNewMode) {
T = Context.getConstantArrayType(T, ConstVal, ASM, ATI.TypeQuals);
}
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
// Unless we're in C++ new mode. ActOnCXXNew will complain about them
// there, and they're hard errors.
if (!getLangOptions().C99 && !CXXNewMode &&
if (!getLangOptions().C99 &&
(ASM != ArrayType::Normal ||
(ArraySize && !ArraySize->isIntegerConstantExpr(Context))))
Diag(D.getIdentifierLoc(), diag::ext_vla);
@@ -617,12 +611,12 @@ bool Sema::UnwrapSimilarPointerTypes(QualType& T1, QualType& T2)
return false;
}
Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D, bool CXXNewMode) {
Sema::TypeResult Sema::ActOnTypeName(Scope *S, Declarator &D) {
// 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, CXXNewMode);
QualType T = GetTypeForDeclarator(D, S);
assert(!T.isNull() && "GetTypeForDeclarator() returned null type");

View File

@@ -16,7 +16,7 @@ void good_news()
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);
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];
@@ -29,7 +29,7 @@ void bad_news(int *ip)
(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.1]; // expected-error {{array size expression must have integral or enumerated type, not 'double'}}
(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}}
@@ -38,6 +38,9 @@ void bad_news(int *ip)
(void)new S(1, 1); // expected-error {{call to constructor of 'S' is ambiguous}}
(void)new const int; // expected-error {{must provide an initializer}}
(void)new float*(ip); // expected-error {{incompatible type initializing 'int *', expected 'float *'}}
// Undefined, but clang should reject it directly.
(void)new int[-1]; // expected-error {{array size is negative}}
(void)new int[*(S*)0]; // expected-error {{array size expression must have integral or enumerated type, not 'struct S'}}
// Some lacking cases due to lack of sema support.
}

View File

@@ -500,8 +500,22 @@ welcome!</p>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.1 [expr.unary.op]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.2 [expr.pre.incr]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.3 [expr.sizeof]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.4 [expr.new]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.5 [expr.delete]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.4 [expr.new]</td>
<td class="advanced" align="center"></td>
<td class="medium" align="center"></td>
<td class="medium" align="center"></td>
<td></td>
<td></td>
</tr>
<tr>
<td>&nbsp;&nbsp;&nbsp;&nbsp;5.3.5 [expr.delete]</td>
<td class="advanced" align="center"></td>
<td class="complete" align="center">&#x2713;</td>
<td class="complete" align="center">&#x2713;</td>
<td></td>
<td></td>
</tr>
<tr><td>&nbsp;&nbsp;5.4 [expr.cast]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;5.5 [expr.mptr.oper]</td><td></td><td></td><td></td><td></td><td></td></tr>
<tr><td>&nbsp;&nbsp;5.6 [expr.mul]</td><td></td><td></td><td></td><td></td><td></td></tr>