Revert "Revert "Make CXXNewExpr contain only a single initialier, and not hold the used constructor itself.""

This reintroduces commit r150682 with a fix for the Bullet benchmark crash.

llvm-svn: 150685
This commit is contained in:
Sebastian Redl 2012-02-16 12:22:20 +00:00
parent c3a3c60040
commit 6047f07e81
18 changed files with 308 additions and 321 deletions

View File

@ -1359,34 +1359,24 @@ public:
class CXXNewExpr : public Expr {
// Was the usage ::new, i.e. is the global new to be used?
bool GlobalNew : 1;
// 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;
// If this is an array allocation, does the usual deallocation
// function for the allocated type want to know the allocated size?
bool UsualArrayDeleteWantsSize : 1;
// Whether the referred constructor (if any) was resolved from an
// overload set having size greater than 1.
bool HadMultipleCandidates : 1;
// The number of placement new arguments.
unsigned NumPlacementArgs : 13;
// The number of constructor arguments. This may be 1 even for non-class
// types; use the pseudo copy constructor.
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.
// What kind of initializer do we have? Could be none, parens, or braces.
// In storage, we distinguish between "none, and no initializer expr", and
// "none, but an implicit initializer expr".
unsigned StoredInitializationStyle : 2;
// Contains an optional array size expression, an optional initialization
// expression, and any number of optional placement 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;
/// \brief The allocated type-source information, as written in the source.
TypeSourceInfo *AllocatedTypeInfo;
@ -1395,29 +1385,33 @@ class CXXNewExpr : public Expr {
/// the source range covering the parenthesized type-id.
SourceRange TypeIdParens;
/// \brief Location of the first token.
SourceLocation StartLoc;
SourceLocation EndLoc;
SourceLocation ConstructorLParen;
SourceLocation ConstructorRParen;
/// \brief Source-range of a paren-delimited initializer.
SourceRange DirectInitRange;
friend class ASTStmtReader;
friend class ASTStmtWriter;
public:
enum InitializationStyle {
NoInit, ///< New-expression has no initializer as written.
CallInit, ///< New-expression has a C++98 paren-delimited initializer.
ListInit ///< New-expression has a C++11 list-initializer.
};
CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
SourceRange TypeIdParens,
Expr *arraySize, CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
bool HadMultipleCandidates,
FunctionDecl *operatorDelete, bool usualArrayDeleteWantsSize,
Expr **placementArgs, unsigned numPlaceArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle, Expr *initializer,
QualType ty, TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceLocation endLoc,
SourceLocation constructorLParen,
SourceLocation constructorRParen);
SourceLocation startLoc, SourceRange directInitRange);
explicit CXXNewExpr(EmptyShell Shell)
: Expr(CXXNewExprClass, Shell), SubExprs(0) { }
void AllocateArgsArray(ASTContext &C, bool isArray, unsigned numPlaceArgs,
unsigned numConsArgs);
bool hasInitializer);
QualType getAllocatedType() const {
assert(getType()->isPointerType());
@ -1443,8 +1437,6 @@ public:
void setOperatorNew(FunctionDecl *D) { OperatorNew = D; }
FunctionDecl *getOperatorDelete() const { return OperatorDelete; }
void setOperatorDelete(FunctionDecl *D) { OperatorDelete = D; }
CXXConstructorDecl *getConstructor() const { return Constructor; }
void setConstructor(CXXConstructorDecl *D) { Constructor = D; }
bool isArray() const { return Array; }
Expr *getArraySize() {
@ -1456,23 +1448,40 @@ public:
unsigned getNumPlacementArgs() const { return NumPlacementArgs; }
Expr **getPlacementArgs() {
return reinterpret_cast<Expr **>(SubExprs + Array);
return reinterpret_cast<Expr **>(SubExprs + Array + hasInitializer());
}
Expr *getPlacementArg(unsigned i) {
assert(i < NumPlacementArgs && "Index out of range");
return cast<Expr>(SubExprs[Array + i]);
return getPlacementArgs()[i];
}
const Expr *getPlacementArg(unsigned i) const {
assert(i < NumPlacementArgs && "Index out of range");
return cast<Expr>(SubExprs[Array + i]);
return const_cast<CXXNewExpr*>(this)->getPlacementArg(i);
}
bool isParenTypeId() const { return TypeIdParens.isValid(); }
SourceRange getTypeIdParens() const { return TypeIdParens; }
bool isGlobalNew() const { return GlobalNew; }
bool hasInitializer() const { return Initializer; }
/// \brief Whether this new-expression has any initializer at all.
bool hasInitializer() const { return StoredInitializationStyle > 0; }
/// \brief The kind of initializer this new-expression has.
InitializationStyle getInitializationStyle() const {
if (StoredInitializationStyle == 0)
return NoInit;
return static_cast<InitializationStyle>(StoredInitializationStyle-1);
}
/// \brief The initializer of this new-expression.
Expr *getInitializer() {
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
}
const Expr *getInitializer() const {
return hasInitializer() ? cast<Expr>(SubExprs[Array]) : 0;
}
/// Answers whether the usual array deallocation function for the
/// allocated type expects the size of the allocation as a
@ -1481,71 +1490,39 @@ public:
return UsualArrayDeleteWantsSize;
}
unsigned getNumConstructorArgs() const { return NumConstructorArgs; }
Expr **getConstructorArgs() {
return reinterpret_cast<Expr **>(SubExprs + Array + NumPlacementArgs);
}
Expr *getConstructorArg(unsigned i) {
assert(i < NumConstructorArgs && "Index out of range");
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
}
const Expr *getConstructorArg(unsigned i) const {
assert(i < NumConstructorArgs && "Index out of range");
return cast<Expr>(SubExprs[Array + NumPlacementArgs + i]);
}
/// \brief Whether the new expression refers a constructor that was
/// resolved from an overloaded set having size greater than 1.
bool hadMultipleCandidates() const { return HadMultipleCandidates; }
void setHadMultipleCandidates(bool V) { HadMultipleCandidates = V; }
typedef ExprIterator arg_iterator;
typedef ConstExprIterator const_arg_iterator;
arg_iterator placement_arg_begin() {
return SubExprs + Array;
return SubExprs + Array + hasInitializer();
}
arg_iterator placement_arg_end() {
return SubExprs + Array + getNumPlacementArgs();
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
const_arg_iterator placement_arg_begin() const {
return SubExprs + Array;
return SubExprs + Array + hasInitializer();
}
const_arg_iterator placement_arg_end() const {
return SubExprs + Array + getNumPlacementArgs();
}
arg_iterator constructor_arg_begin() {
return SubExprs + Array + getNumPlacementArgs();
}
arg_iterator constructor_arg_end() {
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
}
const_arg_iterator constructor_arg_begin() const {
return SubExprs + Array + getNumPlacementArgs();
}
const_arg_iterator constructor_arg_end() const {
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
typedef Stmt **raw_arg_iterator;
raw_arg_iterator raw_arg_begin() { return SubExprs; }
raw_arg_iterator raw_arg_end() {
return SubExprs + Array + getNumPlacementArgs() + getNumConstructorArgs();
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
const_arg_iterator raw_arg_begin() const { return SubExprs; }
const_arg_iterator raw_arg_end() const { return constructor_arg_end(); }
const_arg_iterator raw_arg_end() const {
return SubExprs + Array + hasInitializer() + getNumPlacementArgs();
}
SourceLocation getStartLoc() const { return StartLoc; }
SourceLocation getEndLoc() const { return EndLoc; }
SourceLocation getEndLoc() const;
SourceLocation getConstructorLParen() const { return ConstructorLParen; }
SourceLocation getConstructorRParen() const { return ConstructorRParen; }
SourceRange getDirectInitRange() const { return DirectInitRange; }
SourceRange getSourceRange() const {
return SourceRange(StartLoc, EndLoc);
return SourceRange(getStartLoc(), getEndLoc());
}
static bool classof(const Stmt *T) {
@ -1555,9 +1532,7 @@ public:
// Iterators
child_range children() {
return child_range(&SubExprs[0],
&SubExprs[0] + Array + getNumPlacementArgs()
+ getNumConstructorArgs());
return child_range(raw_arg_begin(), raw_arg_end());
}
};

View File

@ -3194,9 +3194,7 @@ public:
MultiExprArg PlacementArgs,
SourceLocation PlacementRParen,
SourceRange TypeIdParens, Declarator &D,
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen);
Expr *Initializer);
ExprResult BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
MultiExprArg PlacementArgs,
@ -3205,9 +3203,8 @@ public:
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
Expr *ArraySize,
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen,
SourceRange DirectInitRange,
Expr *Initializer,
bool TypeMayContainAuto = true);
bool CheckAllocatedType(QualType AllocType, SourceLocation Loc,

View File

@ -2041,10 +2041,7 @@ Expr::CanThrowResult Expr::CanThrow(ASTContext &C) const {
if (isTypeDependent())
CT = CT_Dependent;
else
CT = MergeCanThrow(
CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew()),
CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getConstructor(),
/*NullThrows*/false));
CT = CanCalleeThrow(C, this, cast<CXXNewExpr>(this)->getOperatorNew());
if (CT == CT_Can)
return CT;
return MergeCanThrow(CT, CanSubExprsThrow(C, this));

View File

@ -45,30 +45,26 @@ SourceRange CXXScalarValueInitExpr::getSourceRange() const {
// CXXNewExpr
CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
Expr **placementArgs, unsigned numPlaceArgs,
SourceRange TypeIdParens, Expr *arraySize,
CXXConstructorDecl *constructor, bool initializer,
Expr **constructorArgs, unsigned numConsArgs,
bool HadMultipleCandidates,
FunctionDecl *operatorDelete,
bool usualArrayDeleteWantsSize, QualType ty,
TypeSourceInfo *AllocatedTypeInfo,
SourceLocation startLoc, SourceLocation endLoc,
SourceLocation constructorLParen,
SourceLocation constructorRParen)
bool usualArrayDeleteWantsSize,
Expr **placementArgs, unsigned numPlaceArgs,
SourceRange typeIdParens, Expr *arraySize,
InitializationStyle initializationStyle,
Expr *initializer, QualType ty,
TypeSourceInfo *allocatedTypeInfo,
SourceLocation startLoc, SourceRange directInitRange)
: Expr(CXXNewExprClass, ty, VK_RValue, OK_Ordinary,
ty->isDependentType(), ty->isDependentType(),
ty->isInstantiationDependentType(),
ty->containsUnexpandedParameterPack()),
GlobalNew(globalNew), Initializer(initializer),
UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
HadMultipleCandidates(HadMultipleCandidates),
SubExprs(0), OperatorNew(operatorNew),
OperatorDelete(operatorDelete), Constructor(constructor),
AllocatedTypeInfo(AllocatedTypeInfo), TypeIdParens(TypeIdParens),
StartLoc(startLoc), EndLoc(endLoc), ConstructorLParen(constructorLParen),
ConstructorRParen(constructorRParen) {
AllocateArgsArray(C, arraySize != 0, numPlaceArgs, numConsArgs);
GlobalNew(globalNew), UsualArrayDeleteWantsSize(usualArrayDeleteWantsSize),
SubExprs(0), OperatorNew(operatorNew), OperatorDelete(operatorDelete),
AllocatedTypeInfo(allocatedTypeInfo), TypeIdParens(typeIdParens),
StartLoc(startLoc), DirectInitRange(directInitRange) {
assert((initializer != 0 || initializationStyle == NoInit) &&
"Only NoInit can have no initializer.");
StoredInitializationStyle = initializer ? initializationStyle + 1 : 0;
AllocateArgsArray(C, arraySize != 0, numPlaceArgs, initializer != 0);
unsigned i = 0;
if (Array) {
if (arraySize->isInstantiationDependent())
@ -80,6 +76,16 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = arraySize;
}
if (initializer) {
if (initializer->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (initializer->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
SubExprs[i++] = initializer;
}
for (unsigned j = 0; j < NumPlacementArgs; ++j) {
if (placementArgs[j]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
@ -88,25 +94,15 @@ CXXNewExpr::CXXNewExpr(ASTContext &C, bool globalNew, FunctionDecl *operatorNew,
SubExprs[i++] = placementArgs[j];
}
for (unsigned j = 0; j < NumConstructorArgs; ++j) {
if (constructorArgs[j]->isInstantiationDependent())
ExprBits.InstantiationDependent = true;
if (constructorArgs[j]->containsUnexpandedParameterPack())
ExprBits.ContainsUnexpandedParameterPack = true;
SubExprs[i++] = constructorArgs[j];
}
}
void CXXNewExpr::AllocateArgsArray(ASTContext &C, bool isArray,
unsigned numPlaceArgs, unsigned numConsArgs){
unsigned numPlaceArgs, bool hasInitializer){
assert(SubExprs == 0 && "SubExprs already allocated");
Array = isArray;
NumPlacementArgs = numPlaceArgs;
NumConstructorArgs = numConsArgs;
unsigned TotalSize = Array + NumPlacementArgs + NumConstructorArgs;
unsigned TotalSize = Array + hasInitializer + NumPlacementArgs;
SubExprs = new (C) Stmt*[TotalSize];
}
@ -115,6 +111,17 @@ bool CXXNewExpr::shouldNullCheckAllocation(ASTContext &Ctx) const {
castAs<FunctionProtoType>()->isNothrow(Ctx);
}
SourceLocation CXXNewExpr::getEndLoc() const {
switch (getInitializationStyle()) {
case NoInit:
return AllocatedTypeInfo->getTypeLoc().getEndLoc();
case CallInit:
return DirectInitRange.getEnd();
case ListInit:
return getInitializer()->getSourceRange().getEnd();
}
}
// CXXDeleteExpr
QualType CXXDeleteExpr::getDestroyedType() const {
const Expr *Arg = getArgument();

View File

@ -2351,10 +2351,20 @@ recurse:
Out << '_';
mangleType(New->getAllocatedType());
if (New->hasInitializer()) {
// FIXME: Does this mean "parenthesized initializer"?
Out << "pi";
for (CXXNewExpr::const_arg_iterator I = New->constructor_arg_begin(),
E = New->constructor_arg_end(); I != E; ++I)
mangleExpression(*I);
const Expr *Init = New->getInitializer();
if (const CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init)) {
// Directly inline the initializers.
for (CXXConstructExpr::const_arg_iterator I = CCE->arg_begin(),
E = CCE->arg_end();
I != E; ++I)
mangleExpression(*I);
} else if (const ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
for (unsigned i = 0, e = PLE->getNumExprs(); i != e; ++i)
mangleExpression(PLE->getExpr(i));
} else
mangleExpression(Init);
}
Out << 'E';
break;

View File

@ -1390,17 +1390,13 @@ void StmtPrinter::VisitCXXNewExpr(CXXNewExpr *E) {
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 << ")";
CXXNewExpr::InitializationStyle InitStyle = E->getInitializationStyle();
if (InitStyle) {
if (InitStyle == CXXNewExpr::CallInit)
OS << "(";
PrintExpr(E->getInitializer());
if (InitStyle == CXXNewExpr::CallInit)
OS << ")";
}
}

View File

@ -825,13 +825,11 @@ void StmtProfiler::VisitCXXNewExpr(const CXXNewExpr *S) {
VisitType(S->getAllocatedType());
VisitDecl(S->getOperatorNew());
VisitDecl(S->getOperatorDelete());
VisitDecl(S->getConstructor());
ID.AddBoolean(S->isArray());
ID.AddInteger(S->getNumPlacementArgs());
ID.AddBoolean(S->isGlobalNew());
ID.AddBoolean(S->isParenTypeId());
ID.AddBoolean(S->hasInitializer());
ID.AddInteger(S->getNumConstructorArgs());
ID.AddInteger(S->getInitializationStyle());
}
void

View File

@ -743,11 +743,8 @@ static llvm::Value *EmitCXXNewAllocSize(CodeGenFunction &CGF,
static void StoreAnyExprIntoOneUnit(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr) {
assert(E->getNumConstructorArgs() == 1 &&
"Can only have one argument to initializer of POD type.");
const Expr *Init = E->getConstructorArg(0);
const Expr *Init = E->getInitializer();
QualType AllocType = E->getAllocatedType();
CharUnits Alignment = CGF.getContext().getTypeAlignInChars(AllocType);
@ -773,9 +770,8 @@ CodeGenFunction::EmitNewArrayInitializer(const CXXNewExpr *E,
QualType elementType,
llvm::Value *beginPtr,
llvm::Value *numElements) {
// We have a POD type.
if (E->getNumConstructorArgs() == 0)
return;
if (!E->hasInitializer())
return; // We have a POD type.
// Check if the number of elements is constant.
bool checkZero = true;
@ -858,13 +854,15 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
llvm::Value *NewPtr,
llvm::Value *NumElements,
llvm::Value *AllocSizeWithoutCookie) {
const Expr *Init = E->getInitializer();
if (E->isArray()) {
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)){
CXXConstructorDecl *Ctor = CCE->getConstructor();
bool RequiresZeroInitialization = false;
if (Ctor->getParent()->hasTrivialDefaultConstructor()) {
// If new expression did not specify value-initialization, then there
// is no initialization.
if (!E->hasInitializer() || Ctor->getParent()->isEmpty())
if (!CCE->requiresZeroInitialization() || Ctor->getParent()->isEmpty())
return;
if (CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
@ -877,43 +875,38 @@ static void EmitNewInitializer(CodeGenFunction &CGF, const CXXNewExpr *E,
RequiresZeroInitialization = true;
}
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
E->constructor_arg_begin(),
E->constructor_arg_end(),
CGF.EmitCXXAggrConstructorCall(Ctor, NumElements, NewPtr,
CCE->arg_begin(), CCE->arg_end(),
RequiresZeroInitialization);
return;
} else if (E->getNumConstructorArgs() == 1 &&
isa<ImplicitValueInitExpr>(E->getConstructorArg(0)) &&
} else if (Init && isa<ImplicitValueInitExpr>(Init) &&
CGF.CGM.getTypes().isZeroInitializable(ElementType)) {
// Optimization: since zero initialization will just set the memory
// to all zeroes, generate a single memset to do it in one shot.
EmitZeroMemSet(CGF, ElementType, NewPtr, AllocSizeWithoutCookie);
return;
} else {
CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
return;
}
CGF.EmitNewArrayInitializer(E, ElementType, NewPtr, NumElements);
return;
}
if (CXXConstructorDecl *Ctor = E->getConstructor()) {
if (const CXXConstructExpr *CCE = dyn_cast_or_null<CXXConstructExpr>(Init)) {
CXXConstructorDecl *Ctor = CCE->getConstructor();
// Per C++ [expr.new]p15, if we have an initializer, then we're performing
// direct initialization. C++ [dcl.init]p5 requires that we
// zero-initialize storage if there are no user-declared constructors.
if (E->hasInitializer() &&
!Ctor->getParent()->hasUserDeclaredConstructor() &&
if (!Ctor->getParent()->hasUserDeclaredConstructor() &&
!Ctor->getParent()->isEmpty())
CGF.EmitNullInitialization(NewPtr, ElementType);
CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
NewPtr, E->constructor_arg_begin(),
E->constructor_arg_end());
CGF.EmitCXXConstructorCall(Ctor, Ctor_Complete, /*ForVirtualBase=*/false,
NewPtr, CCE->arg_begin(), CCE->arg_end());
return;
}
// We have a POD type.
if (E->getNumConstructorArgs() == 0)
if (!Init)
return;
StoreAnyExprIntoOneUnit(CGF, E, NewPtr);
}
@ -1145,7 +1138,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
// CXXNewExpr::shouldNullCheckAllocation()) and we have an
// interesting initializer.
bool nullCheck = allocatorType->isNothrow(getContext()) &&
!(allocType.isPODType(getContext()) && !E->hasInitializer());
(!allocType.isPODType(getContext()) || E->hasInitializer());
llvm::BasicBlock *nullCheckBB = 0;
llvm::BasicBlock *contBB = 0;
@ -1211,7 +1204,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
DeactivateCleanupBlock(operatorDeleteCleanup, cleanupDominator);
cleanupDominator->eraseFromParent();
}
if (nullCheck) {
conditional.end(*this);

View File

@ -2193,10 +2193,11 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
return ExprError();
}
ExprVector ConstructorArgs(Actions);
SourceLocation ConstructorLParen, ConstructorRParen;
ExprResult Initializer;
if (Tok.is(tok::l_paren)) {
SourceLocation ConstructorLParen, ConstructorRParen;
ExprVector ConstructorArgs(Actions);
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
ConstructorLParen = T.getOpenLocation();
@ -2213,19 +2214,20 @@ Parser::ParseCXXNewExpression(bool UseGlobal, SourceLocation Start) {
SkipUntil(tok::semi, /*StopAtSemi=*/true, /*DontConsume=*/true);
return ExprError();
}
Initializer = Actions.ActOnParenListExpr(ConstructorLParen,
ConstructorRParen,
move_arg(ConstructorArgs));
} else if (Tok.is(tok::l_brace) && getLang().CPlusPlus0x) {
Diag(Tok.getLocation(),
diag::warn_cxx98_compat_generalized_initializer_lists);
ExprResult InitList = ParseBraceInitializer();
if (InitList.isInvalid())
return InitList;
ConstructorArgs.push_back(InitList.take());
Initializer = ParseBraceInitializer();
}
if (Initializer.isInvalid())
return Initializer;
return Actions.ActOnCXXNew(Start, UseGlobal, PlacementLParen,
move_arg(PlacementArgs), PlacementRParen,
TypeIdParens, DeclaratorInfo, ConstructorLParen,
move_arg(ConstructorArgs), ConstructorRParen);
TypeIdParens, DeclaratorInfo, Initializer.take());
}
/// ParseDirectNewDeclarator - Parses a direct-new-declarator. Intended to be

View File

@ -10148,15 +10148,13 @@ namespace {
}
void VisitCXXNewExpr(CXXNewExpr *E) {
if (E->getConstructor())
S.MarkFunctionReferenced(E->getLocStart(), E->getConstructor());
if (E->getOperatorNew())
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorNew());
if (E->getOperatorDelete())
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());
Inherited::VisitCXXNewExpr(E);
}
void VisitCXXDeleteExpr(CXXDeleteExpr *E) {
if (E->getOperatorDelete())
S.MarkFunctionReferenced(E->getLocStart(), E->getOperatorDelete());

View File

@ -914,9 +914,7 @@ ExprResult
Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen, MultiExprArg PlacementArgs,
SourceLocation PlacementRParen, SourceRange TypeIdParens,
Declarator &D, SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen) {
Declarator &D, Expr *Initializer) {
bool TypeContainsAuto = D.getDeclSpec().getTypeSpecType() == DeclSpec::TST_auto;
Expr *ArraySize = 0;
@ -961,6 +959,10 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (D.isInvalidType())
return ExprError();
SourceRange DirectInitRange;
if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer))
DirectInitRange = List->getSourceRange();
return BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
move(PlacementArgs),
@ -969,12 +971,27 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal,
AllocType,
TInfo,
ArraySize,
ConstructorLParen,
move(ConstructorArgs),
ConstructorRParen,
DirectInitRange,
Initializer,
TypeContainsAuto);
}
static bool isLegalArrayNewInitializer(Expr *Init) {
if (!Init)
return true;
if (ParenListExpr *PLE = dyn_cast<ParenListExpr>(Init)) {
if (PLE->getNumExprs() != 1)
return PLE->getNumExprs() == 0;
Init = PLE->getExpr(0);
}
if (isa<ImplicitValueInitExpr>(Init))
return true;
else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Init))
return !CCE->isListInitialization() &&
CCE->getConstructor()->isDefaultConstructor();
return false;
}
ExprResult
Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
SourceLocation PlacementLParen,
@ -984,29 +1001,56 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
QualType AllocType,
TypeSourceInfo *AllocTypeInfo,
Expr *ArraySize,
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen,
SourceRange DirectInitRange,
Expr *Initializer,
bool TypeMayContainAuto) {
SourceRange TypeRange = AllocTypeInfo->getTypeLoc().getSourceRange();
CXXNewExpr::InitializationStyle initStyle;
if (DirectInitRange.isValid()) {
assert(Initializer && "Have parens but no initializer.");
initStyle = CXXNewExpr::CallInit;
} else if (Initializer && isa<InitListExpr>(Initializer))
initStyle = CXXNewExpr::ListInit;
else {
assert((!Initializer || isa<ImplicitValueInitExpr>(Initializer) ||
isa<CXXConstructExpr>(Initializer)) &&
"Initializer expression that cannot have been implicitly created.");
initStyle = CXXNewExpr::NoInit;
}
Expr **Inits = &Initializer;
unsigned NumInits = Initializer ? 1 : 0;
if (initStyle == CXXNewExpr::CallInit) {
if (ParenListExpr *List = dyn_cast<ParenListExpr>(Initializer)) {
Inits = List->getExprs();
NumInits = List->getNumExprs();
} else if (CXXConstructExpr *CCE = dyn_cast<CXXConstructExpr>(Initializer)){
if (!isa<CXXTemporaryObjectExpr>(CCE)) {
// Can happen in template instantiation. Since this is just an implicit
// construction, we just take it apart and rebuild it.
Inits = CCE->getArgs();
NumInits = CCE->getNumArgs();
}
}
}
// C++0x [decl.spec.auto]p6. Deduce the type which 'auto' stands in for.
if (TypeMayContainAuto && AllocType->getContainedAutoType()) {
if (ConstructorArgs.size() == 0)
if (initStyle == CXXNewExpr::NoInit || NumInits == 0)
return ExprError(Diag(StartLoc, diag::err_auto_new_requires_ctor_arg)
<< AllocType << TypeRange);
if (ConstructorArgs.size() != 1) {
Expr *FirstBad = ConstructorArgs.get()[1];
if (initStyle == CXXNewExpr::ListInit)
return ExprError(Diag(Inits[0]->getSourceRange().getBegin(),
diag::err_auto_new_requires_parens)
<< AllocType << TypeRange);
if (NumInits > 1) {
Expr *FirstBad = Inits[1];
return ExprError(Diag(FirstBad->getSourceRange().getBegin(),
diag::err_auto_new_ctor_multiple_expressions)
<< AllocType << TypeRange);
}
Expr *Deduce = ConstructorArgs.get()[0];
if (ConstructorLParen.isInvalid()) {
return ExprError(Diag(Deduce->getSourceRange().getBegin(),
diag::err_auto_new_requires_parens)
<< AllocType << TypeRange);
}
Expr *Deduce = Inits[0];
TypeSourceInfo *DeducedType = 0;
if (DeduceAutoType(AllocTypeInfo, Deduce, DeducedType) ==
DAR_Failed)
@ -1035,15 +1079,10 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
if (CheckAllocatedType(AllocType, TypeRange.getBegin(), TypeRange))
return ExprError();
bool ListInitialization = ConstructorLParen.isInvalid() &&
ConstructorArgs.size() > 0;
assert((!ListInitialization || (ConstructorArgs.size() == 1 &&
isa<InitListExpr>(ConstructorArgs.get()[0])))
&& "List initialization means a braced-init-list for arguments.");
if (ListInitialization && isStdInitializerList(AllocType, 0)) {
if (initStyle == CXXNewExpr::ListInit && isStdInitializerList(AllocType, 0)) {
Diag(AllocTypeInfo->getTypeLoc().getBeginLoc(),
diag::warn_dangling_std_initializer_list)
<< /*at end of FE*/0 << ConstructorArgs.get()[0]->getSourceRange();
<< /*at end of FE*/0 << Inits[0]->getSourceRange();
}
// In ARC, infer 'retaining' for the allocated
@ -1201,25 +1240,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
}
bool Init = ConstructorLParen.isValid() || ConstructorArgs.size() > 0;
// --- Choosing a constructor ---
CXXConstructorDecl *Constructor = 0;
bool HadMultipleCandidates = false;
Expr **ConsArgs = (Expr**)ConstructorArgs.get();
unsigned NumConsArgs = ConstructorArgs.size();
ASTOwningVector<Expr*> ConvertedConstructorArgs(*this);
// Array 'new' can't have any initializers.
if (NumConsArgs && (ResultType->isArrayType() || ArraySize)) {
SourceRange InitRange(ConsArgs[0]->getLocStart(),
ConsArgs[NumConsArgs - 1]->getLocEnd());
// Array 'new' can't have any initializers except empty parentheses.
if (!isLegalArrayNewInitializer(Initializer) &&
(ResultType->isArrayType() || ArraySize)) {
SourceRange InitRange(Inits[0]->getLocStart(),
Inits[NumInits - 1]->getLocEnd());
Diag(StartLoc, diag::err_new_array_init_args) << InitRange;
return ExprError();
}
if (!AllocType->isDependentType() &&
!Expr::hasAnyTypeDependentArguments(ConsArgs, NumConsArgs)) {
!Expr::hasAnyTypeDependentArguments(Inits, NumInits)) {
// C++11 [expr.new]p15:
// A new-expression that creates an object of type T initializes that
// object as follows:
@ -1227,49 +1259,31 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// - If the new-initializer is omitted, the object is default-
// initialized (8.5); if no initialization is performed,
// the object has indeterminate value
= !Init? InitializationKind::CreateDefault(TypeRange.getBegin())
= initStyle == CXXNewExpr::NoInit
? InitializationKind::CreateDefault(TypeRange.getBegin())
// - Otherwise, the new-initializer is interpreted according to the
// initialization rules of 8.5 for direct-initialization.
: ListInitialization ? InitializationKind::CreateDirectList(
TypeRange.getBegin())
: InitializationKind::CreateDirect(
TypeRange.getBegin(),
ConstructorLParen,
ConstructorRParen);
: initStyle == CXXNewExpr::ListInit
? InitializationKind::CreateDirectList(TypeRange.getBegin())
: InitializationKind::CreateDirect(TypeRange.getBegin(),
DirectInitRange.getBegin(),
DirectInitRange.getEnd());
InitializedEntity Entity
= InitializedEntity::InitializeNew(StartLoc, AllocType);
InitializationSequence InitSeq(*this, Entity, Kind, ConsArgs, NumConsArgs);
InitializationSequence InitSeq(*this, Entity, Kind, Inits, NumInits);
ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind,
move(ConstructorArgs));
MultiExprArg(Inits, NumInits));
if (FullInit.isInvalid())
return ExprError();
// FullInit is our initializer; walk through it to determine if it's a
// constructor call, which CXXNewExpr handles directly.
if (Expr *FullInitExpr = (Expr *)FullInit.get()) {
if (CXXBindTemporaryExpr *Binder
= dyn_cast<CXXBindTemporaryExpr>(FullInitExpr))
FullInitExpr = Binder->getSubExpr();
if (CXXConstructExpr *Construct
= dyn_cast<CXXConstructExpr>(FullInitExpr)) {
Constructor = Construct->getConstructor();
HadMultipleCandidates = Construct->hadMultipleCandidates();
for (CXXConstructExpr::arg_iterator A = Construct->arg_begin(),
AEnd = Construct->arg_end();
A != AEnd; ++A)
ConvertedConstructorArgs.push_back(*A);
} else {
// Take the converted initializer.
ConvertedConstructorArgs.push_back(FullInit.release());
}
} else {
// No initialization required.
}
// FullInit is our initializer; strip off CXXBindTemporaryExprs, because
// we don't want the initialized object to be destructed.
if (CXXBindTemporaryExpr *Binder =
dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get()))
FullInit = Owned(Binder->getSubExpr());
// Take the converted arguments and use them for the new expression.
NumConsArgs = ConvertedConstructorArgs.size();
ConsArgs = (Expr **)ConvertedConstructorArgs.take();
Initializer = FullInit.take();
}
// Mark the new and delete operators as referenced.
@ -1281,8 +1295,9 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
// C++0x [expr.new]p17:
// If the new expression creates an array of objects of class type,
// access and ambiguity control are done for the destructor.
if (ArraySize && Constructor) {
if (CXXDestructorDecl *dtor = LookupDestructor(Constructor->getParent())) {
if (ArraySize && AllocType->isRecordType() && !AllocType->isDependentType()) {
if (CXXDestructorDecl *dtor = LookupDestructor(
cast<CXXRecordDecl>(AllocType->getAs<RecordType>()->getDecl()))) {
MarkFunctionReferenced(StartLoc, dtor);
CheckDestructorAccess(StartLoc, dtor,
PDiag(diag::err_access_dtor)
@ -1291,25 +1306,18 @@ Sema::BuildCXXNew(SourceLocation StartLoc, bool UseGlobal,
}
PlacementArgs.release();
ConstructorArgs.release();
return Owned(new (Context) CXXNewExpr(Context, UseGlobal, OperatorNew,
PlaceArgs, NumPlaceArgs, TypeIdParens,
ArraySize, Constructor, Init,
ConsArgs, NumConsArgs,
HadMultipleCandidates,
OperatorDelete,
UsualArrayDeleteWantsSize,
PlaceArgs, NumPlaceArgs, TypeIdParens,
ArraySize, initStyle, Initializer,
ResultType, AllocTypeInfo,
StartLoc,
Init ? ConstructorRParen :
TypeRange.getEnd(),
ConstructorLParen, ConstructorRParen));
StartLoc, DirectInitRange));
}
/// CheckAllocatedType - Checks that a type is suitable as the allocated type
/// \brief 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 Loc,
SourceRange R) {
// C++ 5.3.4p1: "[The] type shall be a complete object type, but not an

View File

@ -1976,9 +1976,8 @@ public:
QualType AllocatedType,
TypeSourceInfo *AllocatedTypeInfo,
Expr *ArraySize,
SourceLocation ConstructorLParen,
MultiExprArg ConstructorArgs,
SourceLocation ConstructorRParen) {
SourceRange DirectInitRange,
Expr *Initializer) {
return getSema().BuildCXXNew(StartLoc, UseGlobal,
PlacementLParen,
move(PlacementArgs),
@ -1987,9 +1986,8 @@ public:
AllocatedType,
AllocatedTypeInfo,
ArraySize,
ConstructorLParen,
move(ConstructorArgs),
ConstructorRParen);
DirectInitRange,
Initializer);
}
/// \brief Build a new C++ "delete" expression.
@ -7106,29 +7104,17 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (getDerived().TransformExprs(E->getPlacementArgs(),
E->getNumPlacementArgs(), true,
PlacementArgs, &ArgumentChanged))
return ExprError();
return ExprError();
// Transform the constructor arguments (if any).
// As an annoying corner case, we may have introduced an implicit value-
// initialization expression when allocating a new array, which we implicitly
// drop. It will be re-created during type checking.
ASTOwningVector<Expr*> ConstructorArgs(SemaRef);
if (!(E->isArray() && E->getNumConstructorArgs() == 1 &&
isa<ImplicitValueInitExpr>(E->getConstructorArgs()[0])) &&
TransformExprs(E->getConstructorArgs(), E->getNumConstructorArgs(), true,
ConstructorArgs, &ArgumentChanged))
return ExprError();
// Transform constructor, new operator, and delete operator.
CXXConstructorDecl *Constructor = 0;
if (E->getConstructor()) {
Constructor = cast_or_null<CXXConstructorDecl>(
getDerived().TransformDecl(E->getLocStart(),
E->getConstructor()));
if (!Constructor)
return ExprError();
}
// Transform the initializer (if any).
Expr *OldInit = E->getInitializer();
ExprResult NewInit;
if (OldInit)
NewInit = getDerived().TransformExpr(OldInit);
if (NewInit.isInvalid())
return ExprError();
// Transform new operator and delete operator.
FunctionDecl *OperatorNew = 0;
if (E->getOperatorNew()) {
OperatorNew = cast_or_null<FunctionDecl>(
@ -7150,21 +7136,18 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
if (!getDerived().AlwaysRebuild() &&
AllocTypeInfo == E->getAllocatedTypeSourceInfo() &&
ArraySize.get() == E->getArraySize() &&
Constructor == E->getConstructor() &&
NewInit.get() == OldInit &&
OperatorNew == E->getOperatorNew() &&
OperatorDelete == E->getOperatorDelete() &&
!ArgumentChanged) {
// Mark any declarations we need as referenced.
// FIXME: instantiation-specific.
if (Constructor)
SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
if (OperatorNew)
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorNew);
if (OperatorDelete)
SemaRef.MarkFunctionReferenced(E->getLocStart(), OperatorDelete);
if (E->isArray() && Constructor &&
!E->getAllocatedType()->isDependentType()) {
if (E->isArray() && !E->getAllocatedType()->isDependentType()) {
QualType ElementType
= SemaRef.Context.getBaseElementType(E->getAllocatedType());
if (const RecordType *RecordT = ElementType->getAs<RecordType>()) {
@ -7174,7 +7157,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
}
}
return SemaRef.Owned(E);
}
@ -7204,7 +7187,7 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
}
}
}
return getDerived().RebuildCXXNewExpr(E->getLocStart(),
E->isGlobalNew(),
/*FIXME:*/E->getLocStart(),
@ -7214,9 +7197,8 @@ TreeTransform<Derived>::TransformCXXNewExpr(CXXNewExpr *E) {
AllocType,
AllocTypeInfo,
ArraySize.get(),
E->getConstructorLParen(),
move_arg(ConstructorArgs),
E->getConstructorRParen());
E->getDirectInitRange(),
NewInit.take());
}
template<typename Derived>

View File

@ -1167,27 +1167,24 @@ void ASTStmtReader::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
void ASTStmtReader::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
E->GlobalNew = Record[Idx++];
E->Initializer = Record[Idx++];
E->UsualArrayDeleteWantsSize = Record[Idx++];
bool isArray = Record[Idx++];
E->setHadMultipleCandidates(Record[Idx++]);
E->UsualArrayDeleteWantsSize = Record[Idx++];
unsigned NumPlacementArgs = Record[Idx++];
unsigned NumCtorArgs = Record[Idx++];
E->StoredInitializationStyle = Record[Idx++];
E->setOperatorNew(ReadDeclAs<FunctionDecl>(Record, Idx));
E->setOperatorDelete(ReadDeclAs<FunctionDecl>(Record, Idx));
E->setConstructor(ReadDeclAs<CXXConstructorDecl>(Record, Idx));
E->AllocatedTypeInfo = GetTypeSourceInfo(Record, Idx);
SourceRange TypeIdParens;
TypeIdParens.setBegin(ReadSourceLocation(Record, Idx));
TypeIdParens.setEnd(ReadSourceLocation(Record, Idx));
E->TypeIdParens = TypeIdParens;
E->StartLoc = ReadSourceLocation(Record, Idx);
E->EndLoc = ReadSourceLocation(Record, Idx);
E->ConstructorLParen = ReadSourceLocation(Record, Idx);
E->ConstructorRParen = ReadSourceLocation(Record, Idx);
SourceRange DirectInitRange;
DirectInitRange.setBegin(ReadSourceLocation(Record, Idx));
DirectInitRange.setEnd(ReadSourceLocation(Record, Idx));
E->AllocateArgsArray(Reader.getContext(), isArray, NumPlacementArgs,
NumCtorArgs);
E->StoredInitializationStyle != 0);
// Install all the subexpressions.
for (CXXNewExpr::raw_arg_iterator I = E->raw_arg_begin(),e = E->raw_arg_end();

View File

@ -1158,25 +1158,20 @@ void ASTStmtWriter::VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E) {
void ASTStmtWriter::VisitCXXNewExpr(CXXNewExpr *E) {
VisitExpr(E);
Record.push_back(E->isGlobalNew());
Record.push_back(E->hasInitializer());
Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->isArray());
Record.push_back(E->hadMultipleCandidates());
Record.push_back(E->doesUsualArrayDeleteWantSize());
Record.push_back(E->getNumPlacementArgs());
Record.push_back(E->getNumConstructorArgs());
Record.push_back(E->StoredInitializationStyle);
Writer.AddDeclRef(E->getOperatorNew(), Record);
Writer.AddDeclRef(E->getOperatorDelete(), Record);
Writer.AddDeclRef(E->getConstructor(), Record);
Writer.AddTypeSourceInfo(E->getAllocatedTypeSourceInfo(), Record);
Writer.AddSourceRange(E->getTypeIdParens(), Record);
Writer.AddSourceLocation(E->getStartLoc(), Record);
Writer.AddSourceLocation(E->getEndLoc(), Record);
Writer.AddSourceLocation(E->getConstructorLParen(), Record);
Writer.AddSourceLocation(E->getConstructorRParen(), Record);
Writer.AddSourceRange(E->getDirectInitRange(), Record);
for (CXXNewExpr::arg_iterator I = E->raw_arg_begin(), e = E->raw_arg_end();
I != e; ++I)
Writer.AddStmt(*I);
Code = serialization::EXPR_CXX_NEW;
}

View File

@ -268,6 +268,8 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
return;
}
// FIXME: Update for AST changes.
#if 0
// Evaluate constructor arguments.
const FunctionProtoType *FnType = NULL;
const CXXConstructorDecl *CD = CNE->getConstructor();
@ -327,6 +329,7 @@ void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred,
loc::MemRegionVal(EleReg));
Bldr.generateNode(CNE, *I, state);
}
#endif
}
void ExprEngine::VisitCXXDeleteExpr(const CXXDeleteExpr *CDE,

View File

@ -1,4 +1,5 @@
// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -verify %s
// XFAIL: *
void f1() {
int *n = new int;

View File

@ -417,3 +417,32 @@ namespace PR10504 {
};
void f(A *x) { delete x; } // expected-warning {{delete called on 'PR10504::A' that is abstract but has non-virtual destructor}}
}
struct PlacementArg {};
inline void *operator new[](size_t, const PlacementArg &) throw () {
return 0;
}
inline void operator delete[](void *, const PlacementArg &) throw () {
}
namespace r150682 {
template <typename X>
struct S {
struct Inner {};
S() { new Inner[1]; }
};
struct T {
};
template<typename X>
void tfn() {
new (*(PlacementArg*)0) T[1];
}
void fn() {
tfn<int>();
}
}

View File

@ -1856,9 +1856,8 @@ VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) {
AddStmt(E->getBase());
}
void EnqueueVisitor::VisitCXXNewExpr(CXXNewExpr *E) {
// Enqueue the initializer or constructor arguments.
for (unsigned I = E->getNumConstructorArgs(); I > 0; --I)
AddStmt(E->getConstructorArg(I-1));
// Enqueue the initializer , if any.
AddStmt(E->getInitializer());
// Enqueue the array size, if any.
AddStmt(E->getArraySize());
// Enqueue the allocated type.